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"
63 * Remove all these #ifdef stuff when the tinymail's idle calls become
66 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
68 /* 'private'/'protected' functions */
69 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
70 static void modest_mail_operation_init (ModestMailOperation *obj);
71 static void modest_mail_operation_finalize (GObject *obj);
73 static void get_msg_cb (TnyFolder *folder,
79 static void get_msg_status_cb (GObject *obj,
83 static void modest_mail_operation_notify_end (ModestMailOperation *self);
85 enum _ModestMailOperationSignals
87 PROGRESS_CHANGED_SIGNAL,
92 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
93 struct _ModestMailOperationPrivate {
100 ErrorCheckingUserCallback error_checking;
101 gpointer error_checking_user_data;
102 ModestMailOperationStatus status;
103 ModestMailOperationTypeOperation op_type;
106 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
107 MODEST_TYPE_MAIL_OPERATION, \
108 ModestMailOperationPrivate))
110 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
111 priv->status = new_status;\
114 typedef struct _GetMsgAsyncHelper {
115 ModestMailOperation *mail_op;
117 GetMsgAsyncUserCallback user_callback;
121 typedef struct _RefreshAsyncHelper {
122 ModestMailOperation *mail_op;
123 RefreshAsyncUserCallback user_callback;
125 } RefreshAsyncHelper;
127 typedef struct _XFerMsgAsyncHelper
129 ModestMailOperation *mail_op;
131 TnyFolder *dest_folder;
132 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 g_return_val_if_fail (priv->account, FALSE);
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 /* This is a GDK lock because we are an idle callback and
579 * info->callback can contain Gtk+ code */
581 gdk_threads_enter (); /* CHECKED */
582 info->callback (info->mail_op, info->msg, info->userdata);
583 gdk_threads_leave (); /* CHECKED */
585 g_object_unref (info->mail_op);
587 g_object_unref (info->msg);
588 g_slice_free (CreateMsgIdleInfo, info);
594 create_msg_thread (gpointer thread_data)
596 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
597 TnyMsg *new_msg = NULL;
598 ModestMailOperationPrivate *priv;
600 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
601 if (info->html_body == NULL) {
602 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
603 info->bcc, info->subject, info->plain_body,
604 info->attachments_list); /* FIXME: attachments */
606 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
607 info->bcc, info->subject, info->html_body,
608 info->plain_body, info->attachments_list);
613 TnyHeaderFlags flags = 0;
615 /* Set priority flags in message */
616 header = tny_msg_get_header (new_msg);
617 if (info->priority_flags != 0)
618 flags |= info->priority_flags;
620 /* Set attachment flags in message */
621 if (info->attachments_list != NULL)
622 flags |= TNY_HEADER_FLAG_ATTACHMENTS;
624 tny_header_set_flags (header, flags);
625 g_object_unref (G_OBJECT(header));
627 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
628 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
629 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
630 "modest: failed to create a new msg\n");
638 g_free (info->plain_body);
639 g_free (info->html_body);
640 g_free (info->subject);
641 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
642 g_list_free (info->attachments_list);
644 if (info->callback) {
645 CreateMsgIdleInfo *idle_info;
646 idle_info = g_slice_new0 (CreateMsgIdleInfo);
647 idle_info->mail_op = info->mail_op;
648 g_object_ref (info->mail_op);
649 idle_info->msg = new_msg;
651 g_object_ref (new_msg);
652 idle_info->callback = info->callback;
653 idle_info->userdata = info->userdata;
654 g_idle_add (idle_create_msg_cb, idle_info);
656 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
659 g_object_unref (info->mail_op);
660 g_slice_free (CreateMsgInfo, info);
665 modest_mail_operation_create_msg (ModestMailOperation *self,
666 const gchar *from, const gchar *to,
667 const gchar *cc, const gchar *bcc,
668 const gchar *subject, const gchar *plain_body,
669 const gchar *html_body,
670 const GList *attachments_list,
671 TnyHeaderFlags priority_flags,
672 ModestMailOperationCreateMsgCallback callback,
675 CreateMsgInfo *info = NULL;
677 info = g_slice_new0 (CreateMsgInfo);
678 info->mail_op = self;
681 info->from = g_strdup (from);
682 info->to = g_strdup (to);
683 info->cc = g_strdup (cc);
684 info->bcc = g_strdup (bcc);
685 info->subject = g_strdup (subject);
686 info->plain_body = g_strdup (plain_body);
687 info->html_body = g_strdup (html_body);
688 info->attachments_list = g_list_copy ((GList *) attachments_list);
689 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
690 info->priority_flags = priority_flags;
692 info->callback = callback;
693 info->userdata = userdata;
695 g_thread_create (create_msg_thread, info, FALSE, NULL);
700 TnyTransportAccount *transport_account;
705 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
709 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
710 TnyFolder *draft_folder = NULL;
711 TnyFolder *outbox_folder = NULL;
718 /* Call mail operation */
719 modest_mail_operation_send_mail (self, info->transport_account, msg);
721 /* Remove old mail from its source folder */
722 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
723 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_OUTBOX);
724 if (info->draft_msg != NULL) {
725 TnyFolder *folder = NULL;
726 TnyFolder *src_folder = NULL;
727 TnyFolderType folder_type;
728 folder = tny_msg_get_folder (info->draft_msg);
729 if (folder == NULL) goto end;
730 folder_type = modest_tny_folder_guess_folder_type (folder);
731 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
732 src_folder = outbox_folder;
734 src_folder = draft_folder;
736 /* Note: This can fail (with a warning) if the message is not really already in a folder,
737 * because this function requires it to have a UID. */
738 header = tny_msg_get_header (info->draft_msg);
739 tny_folder_remove_msg (src_folder, header, NULL);
740 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
741 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
742 g_object_unref (header);
743 g_object_unref (folder);
748 g_object_unref (info->draft_msg);
750 g_object_unref (draft_folder);
752 g_object_unref (outbox_folder);
753 if (info->transport_account)
754 g_object_unref (info->transport_account);
755 g_slice_free (SendNewMailInfo, info);
756 modest_mail_operation_notify_end (self);
760 modest_mail_operation_send_new_mail (ModestMailOperation *self,
761 TnyTransportAccount *transport_account,
763 const gchar *from, const gchar *to,
764 const gchar *cc, const gchar *bcc,
765 const gchar *subject, const gchar *plain_body,
766 const gchar *html_body,
767 const GList *attachments_list,
768 TnyHeaderFlags priority_flags)
770 ModestMailOperationPrivate *priv = NULL;
771 SendNewMailInfo *info;
773 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
774 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
776 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
778 /* Check parametters */
780 /* Set status failed and set an error */
781 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
782 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
783 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
784 _("Error trying to send a mail. You need to set at least one recipient"));
787 info = g_slice_new0 (SendNewMailInfo);
788 info->transport_account = transport_account;
789 if (transport_account)
790 g_object_ref (transport_account);
791 info->draft_msg = draft_msg;
793 g_object_ref (draft_msg);
794 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
795 attachments_list, priority_flags,
796 modest_mail_operation_send_new_mail_cb, info);
802 TnyTransportAccount *transport_account;
804 ModestMsgEditWindow *edit_window;
808 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
812 TnyFolder *src_folder = NULL;
813 TnyFolder *folder = NULL;
814 TnyHeader *header = NULL;
815 ModestMailOperationPrivate *priv = NULL;
816 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
818 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
820 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
821 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
822 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
823 "modest: failed to create a new msg\n");
827 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
829 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
830 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
831 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
832 "modest: failed to create a new msg\n");
837 tny_folder_add_msg (folder, msg, &(priv->error));
839 if ((!priv->error) && (info->draft_msg != NULL)) {
840 header = tny_msg_get_header (info->draft_msg);
841 src_folder = tny_header_get_folder (header);
842 /* Remove the old draft expunging it */
843 tny_folder_remove_msg (src_folder, header, NULL);
844 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
845 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
846 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */
847 g_object_unref (header);
851 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
853 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
855 if (info->edit_window)
856 modest_msg_edit_window_set_draft (info->edit_window, msg);
861 g_object_unref (G_OBJECT(folder));
863 g_object_unref (G_OBJECT(src_folder));
864 if (info->edit_window)
865 g_object_unref (G_OBJECT(info->edit_window));
867 g_object_unref (G_OBJECT (info->draft_msg));
868 if (info->transport_account)
869 g_object_unref (G_OBJECT(info->transport_account));
870 g_slice_free (SaveToDraftsInfo, info);
872 modest_mail_operation_notify_end (self);
876 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
877 TnyTransportAccount *transport_account,
879 ModestMsgEditWindow *edit_window,
880 const gchar *from, const gchar *to,
881 const gchar *cc, const gchar *bcc,
882 const gchar *subject, const gchar *plain_body,
883 const gchar *html_body,
884 const GList *attachments_list,
885 TnyHeaderFlags priority_flags)
887 ModestMailOperationPrivate *priv = NULL;
888 SaveToDraftsInfo *info = NULL;
890 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
891 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
893 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
895 /* Get account and set it into mail_operation */
896 priv->account = g_object_ref (transport_account);
898 info = g_slice_new0 (SaveToDraftsInfo);
899 info->transport_account = g_object_ref (transport_account);
900 info->draft_msg = draft_msg;
902 g_object_ref (draft_msg);
903 info->edit_window = edit_window;
905 g_object_ref (edit_window);
907 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
908 attachments_list, priority_flags,
909 modest_mail_operation_save_to_drafts_cb, info);
915 ModestMailOperation *mail_op;
916 TnyStoreAccount *account;
917 TnyTransportAccount *transport_account;
920 gchar *retrieve_type;
922 UpdateAccountCallback callback;
929 ModestMailOperation *mail_op;
930 TnyMimePart *mime_part;
932 GetMimePartSizeCallback callback;
934 } GetMimePartSizeInfo;
936 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
937 /* We use this folder observer to track the headers that have been
938 * added to a folder */
941 TnyList *new_headers;
942 } InternalFolderObserver;
946 } InternalFolderObserverClass;
948 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
950 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
951 internal_folder_observer,
953 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
957 foreach_add_item (gpointer header, gpointer user_data)
959 tny_list_prepend (TNY_LIST (user_data),
960 g_object_ref (G_OBJECT (header)));
963 /* This is the method that looks for new messages in a folder */
965 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
967 InternalFolderObserver *derived = (InternalFolderObserver *)self;
969 TnyFolderChangeChanged changed;
971 changed = tny_folder_change_get_changed (change);
973 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
976 /* Get added headers */
977 list = tny_simple_list_new ();
978 tny_folder_change_get_added_headers (change, list);
980 /* Add them to the folder observer */
981 tny_list_foreach (list, foreach_add_item,
982 derived->new_headers);
984 g_object_unref (G_OBJECT (list));
989 internal_folder_observer_init (InternalFolderObserver *self)
991 self->new_headers = tny_simple_list_new ();
994 internal_folder_observer_finalize (GObject *object)
996 InternalFolderObserver *self;
998 self = (InternalFolderObserver *) object;
999 g_object_unref (self->new_headers);
1001 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1004 tny_folder_observer_init (TnyFolderObserverIface *iface)
1006 iface->update_func = internal_folder_observer_update;
1009 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1011 GObjectClass *object_class;
1013 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1014 object_class = (GObjectClass*) klass;
1015 object_class->finalize = internal_folder_observer_finalize;
1021 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
1024 TnyList *folders = tny_simple_list_new ();
1026 tny_folder_store_get_folders (store, folders, query, NULL);
1027 iter = tny_list_create_iterator (folders);
1029 while (!tny_iterator_is_done (iter)) {
1031 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1033 tny_list_prepend (all_folders, G_OBJECT (folder));
1034 recurse_folders (folder, query, all_folders);
1035 g_object_unref (G_OBJECT (folder));
1038 tny_iterator_next (iter);
1040 g_object_unref (G_OBJECT (iter));
1041 g_object_unref (G_OBJECT (folders));
1045 * Issues the "progress-changed" signal. The timer won't be removed,
1046 * so you must call g_source_remove to stop the signal emission
1049 idle_notify_progress (gpointer data)
1051 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1052 ModestMailOperationState *state;
1054 state = modest_mail_operation_clone_state (mail_op);
1056 /* This is a GDK lock because we are an idle callback and
1057 * the handlers of this signal can contain Gtk+ code */
1059 gdk_threads_enter (); /* CHECKED */
1060 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1061 gdk_threads_leave (); /* CHECKED */
1063 g_slice_free (ModestMailOperationState, state);
1069 * Issues the "progress-changed" signal and removes the timer. It uses
1070 * a lock to ensure that the progress information of the mail
1071 * operation is not modified while there are notifications pending
1074 idle_notify_progress_once (gpointer data)
1078 pair = (ModestPair *) data;
1080 /* This is a GDK lock because we are an idle callback and
1081 * the handlers of this signal can contain Gtk+ code */
1083 gdk_threads_enter (); /* CHECKED */
1084 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1085 gdk_threads_leave (); /* CHECKED */
1087 /* Free the state and the reference to the mail operation */
1088 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1089 g_object_unref (pair->first);
1095 * Used to notify the queue from the main
1096 * loop. We call it inside an idle call to achieve that
1099 idle_notify_queue (gpointer data)
1101 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1103 /* Do not need to block, the notify end will do it for us */
1104 modest_mail_operation_notify_end (mail_op);
1105 g_object_unref (mail_op);
1111 compare_headers_by_date (gconstpointer a,
1114 TnyHeader **header1, **header2;
1115 time_t sent1, sent2;
1117 header1 = (TnyHeader **) a;
1118 header2 = (TnyHeader **) b;
1120 sent1 = tny_header_get_date_sent (*header1);
1121 sent2 = tny_header_get_date_sent (*header2);
1123 /* We want the most recent ones (greater time_t) at the
1132 set_last_updated_idle (gpointer data)
1135 /* This is a GDK lock because we are an idle callback and
1136 * modest_account_mgr_set_int can contain Gtk+ code */
1138 gdk_threads_enter (); /* CHECKED - please recheck */
1140 /* It does not matter if the time is not exactly the same than
1141 the time when this idle was called, it's just an
1142 approximation and it won't be very different */
1144 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1146 MODEST_ACCOUNT_LAST_UPDATED,
1150 gdk_threads_leave (); /* CHECKED - please recheck */
1156 idle_update_account_cb (gpointer data)
1158 UpdateAccountInfo *idle_info;
1160 idle_info = (UpdateAccountInfo *) data;
1162 /* This is a GDK lock because we are an idle callback and
1163 * idle_info->callback can contain Gtk+ code */
1165 gdk_threads_enter (); /* CHECKED */
1166 idle_info->callback (idle_info->mail_op,
1167 idle_info->new_headers,
1168 idle_info->user_data);
1169 gdk_threads_leave (); /* CHECKED */
1172 g_object_unref (idle_info->mail_op);
1180 update_account_thread (gpointer thr_user_data)
1182 static gboolean first_time = TRUE;
1183 UpdateAccountInfo *info = NULL;
1184 TnyList *all_folders = NULL;
1185 GPtrArray *new_headers = NULL;
1186 TnyIterator *iter = NULL;
1187 TnyFolderStoreQuery *query = NULL;
1188 ModestMailOperationPrivate *priv = NULL;
1189 ModestTnySendQueue *send_queue = NULL;
1190 gint num_new_headers = 0;
1192 info = (UpdateAccountInfo *) thr_user_data;
1193 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1195 /* Get account and set it into mail_operation */
1196 priv->account = g_object_ref (info->account);
1199 * Previousl, we did this for POP3, to do a logout-login upon send/receive,
1200 * because many POP-servers (like Gmail) do not
1201 * show any updates unless we do that.
1202 * But that didn't work with gmail anyway,
1203 * and tinymail now takes care of this itself by disconnecting
1204 * automatically after using the connection.
1207 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT (priv->account))
1208 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1211 /* Get all the folders. We can do it synchronously because
1212 we're already running in a different thread than the UI */
1213 all_folders = tny_simple_list_new ();
1214 query = tny_folder_store_query_new ();
1215 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1216 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1221 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1225 iter = tny_list_create_iterator (all_folders);
1226 while (!tny_iterator_is_done (iter)) {
1227 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1229 recurse_folders (folder, query, all_folders);
1230 g_object_unref (folder);
1232 tny_iterator_next (iter);
1234 g_object_unref (G_OBJECT (iter));
1236 /* Update status and notify. We need to call the notification
1237 with a source function in order to call it from the main
1238 loop. We need that in order not to get into trouble with
1239 Gtk+. We use a timeout in order to provide more status
1240 information, because the sync tinymail call does not
1241 provide it for the moment */
1242 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1244 /* Refresh folders */
1245 num_new_headers = 0;
1246 new_headers = g_ptr_array_new ();
1247 iter = tny_list_create_iterator (all_folders);
1249 while (!tny_iterator_is_done (iter) && !priv->error &&
1250 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1252 InternalFolderObserver *observer;
1253 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1255 /* Refresh the folder */
1256 /* Our observer receives notification of new emails during folder refreshes,
1257 * so we can use observer->new_headers.
1259 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1260 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1262 /* This gets the status information (headers) from the server.
1263 * We use the blocking version, because we are already in a separate
1267 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1268 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1271 /* If the retrieve type is full messages, refresh and get the messages */
1272 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1274 iter = tny_list_create_iterator (observer->new_headers);
1275 while (!tny_iterator_is_done (iter)) {
1276 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1278 /* Apply per-message size limits */
1279 if (tny_header_get_message_size (header) < info->max_size)
1280 g_ptr_array_add (new_headers, g_object_ref (header));
1282 g_object_unref (header);
1283 tny_iterator_next (iter);
1285 g_object_unref (iter);
1287 /* We do not need to do it the first time
1288 because it's automatically done by the tree
1290 if (G_UNLIKELY (!first_time))
1291 tny_folder_poke_status (TNY_FOLDER (folder));
1293 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1294 g_object_unref (observer);
1298 g_object_unref (G_OBJECT (folder));
1301 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1303 tny_iterator_next (iter);
1306 g_object_unref (G_OBJECT (iter));
1307 g_source_remove (timeout);
1309 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1310 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1311 new_headers->len > 0) {
1315 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1317 /* Apply message count limit */
1318 /* If the number of messages exceeds the maximum, ask the
1319 * user to download them all,
1320 * as per the UI spec "Retrieval Limits" section in 4.4:
1322 if (new_headers->len > info->retrieve_limit) {
1323 /* TODO: Ask the user, instead of just
1325 * mail_nc_msg_count_limit_exceeded, with 'Get
1326 * all' and 'Newest only' buttons. */
1327 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1328 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1329 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1330 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1331 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1336 priv->total = MIN (new_headers->len, info->retrieve_limit);
1337 while (msg_num < priv->total) {
1339 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1340 TnyFolder *folder = tny_header_get_folder (header);
1341 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1342 ModestMailOperationState *state;
1346 /* We can not just use the mail operation because the
1347 values of done and total could change before the
1349 state = modest_mail_operation_clone_state (info->mail_op);
1350 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1351 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1352 pair, (GDestroyNotify) modest_pair_free);
1354 g_object_unref (msg);
1355 g_object_unref (folder);
1361 /* Get the number of new headers and free them */
1362 num_new_headers = new_headers->len;
1363 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1364 g_ptr_array_free (new_headers, FALSE);
1366 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1369 /* Perform send (if operation was not cancelled) */
1372 if (priv->account != NULL)
1373 g_object_unref (priv->account);
1374 priv->account = g_object_ref (info->transport_account);
1376 send_queue = modest_runtime_get_send_queue (info->transport_account);
1378 modest_tny_send_queue_try_to_send (send_queue);
1380 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1381 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1382 "cannot create a send queue for %s\n",
1383 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1384 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1387 /* Check if the operation was a success */
1389 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1391 /* Update the last updated key */
1392 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1393 set_last_updated_idle,
1394 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1395 (GDestroyNotify) g_free);
1400 if (info->callback) {
1401 UpdateAccountInfo *idle_info;
1403 /* This thread is not in the main lock */
1404 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1405 idle_info->mail_op = g_object_ref (info->mail_op);
1406 idle_info->new_headers = num_new_headers;
1407 idle_info->callback = info->callback;
1408 idle_info->user_data = info->user_data;
1409 g_idle_add (idle_update_account_cb, idle_info);
1412 /* Notify about operation end. Note that the info could be
1413 freed before this idle happens, but the mail operation will
1415 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1418 g_object_unref (query);
1419 g_object_unref (all_folders);
1420 g_object_unref (info->account);
1421 g_object_unref (info->transport_account);
1422 g_free (info->retrieve_type);
1423 g_slice_free (UpdateAccountInfo, info);
1431 modest_mail_operation_update_account (ModestMailOperation *self,
1432 const gchar *account_name,
1433 UpdateAccountCallback callback,
1436 GThread *thread = NULL;
1437 UpdateAccountInfo *info = NULL;
1438 ModestMailOperationPrivate *priv = NULL;
1439 ModestAccountMgr *mgr = NULL;
1440 TnyStoreAccount *store_account = NULL;
1441 TnyTransportAccount *transport_account = NULL;
1443 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1444 g_return_val_if_fail (account_name, FALSE);
1446 /* Init mail operation. Set total and done to 0, and do not
1447 update them, this way the progress objects will know that
1448 we have no clue about the number of the objects */
1449 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1452 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1454 /* Get the Modest account */
1455 store_account = (TnyStoreAccount *)
1456 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1458 TNY_ACCOUNT_TYPE_STORE);
1460 /* Make sure that we have a connection, and request one
1462 * TODO: Is there some way to trigger this for every attempt to
1463 * use the network? */
1464 if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
1467 if (!store_account) {
1468 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1469 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1470 "cannot get tny store account for %s\n", account_name);
1475 /* Get the transport account, we can not do it in the thread
1476 due to some problems with dbus */
1477 transport_account = (TnyTransportAccount *)
1478 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1480 if (!transport_account) {
1481 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1482 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1483 "cannot get tny transport account for %s\n", account_name);
1487 /* Create the helper object */
1488 info = g_slice_new (UpdateAccountInfo);
1489 info->mail_op = self;
1490 info->account = store_account;
1491 info->transport_account = transport_account;
1492 info->callback = callback;
1493 info->user_data = user_data;
1495 /* Get the message size limit */
1496 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1497 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1498 if (info->max_size == 0)
1499 info->max_size = G_MAXINT;
1501 info->max_size = info->max_size * KB;
1503 /* Get per-account retrieval type */
1504 mgr = modest_runtime_get_account_mgr ();
1505 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1506 MODEST_ACCOUNT_RETRIEVE, FALSE);
1508 /* Get per-account message amount retrieval limit */
1509 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1510 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1511 if (info->retrieve_limit == 0)
1512 info->retrieve_limit = G_MAXINT;
1514 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1516 /* Set account busy */
1517 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1518 priv->account_name = g_strdup(account_name);
1520 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1525 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1527 callback (self, 0, user_data);
1528 modest_mail_operation_notify_end (self);
1532 /* ******************************************************************* */
1533 /* ************************** STORE ACTIONS ************************* */
1534 /* ******************************************************************* */
1538 modest_mail_operation_create_folder (ModestMailOperation *self,
1539 TnyFolderStore *parent,
1542 ModestMailOperationPrivate *priv;
1543 TnyFolder *new_folder = NULL;
1545 TnyList *list = tny_simple_list_new ();
1546 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1548 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1549 g_return_val_if_fail (name, NULL);
1551 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1553 /* Check for already existing folder */
1554 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1555 tny_folder_store_get_folders (parent, list, query, NULL);
1556 g_object_unref (G_OBJECT (query));
1558 if (tny_list_get_length (list) > 0) {
1559 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1560 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1561 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1562 _CS("ckdg_ib_folder_already_exists"));
1565 g_object_unref (G_OBJECT (list));
1568 if (TNY_IS_FOLDER (parent)) {
1569 /* Check folder rules */
1570 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1571 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1572 /* Set status failed and set an error */
1573 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1574 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1575 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1576 _("mail_in_ui_folder_create_error"));
1580 if (!strcmp (name, " ") || strchr (name, '/')) {
1581 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1582 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1583 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1584 _("mail_in_ui_folder_create_error"));
1588 /* Create the folder */
1589 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1590 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1592 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1595 /* Notify about operation end */
1596 modest_mail_operation_notify_end (self);
1602 modest_mail_operation_remove_folder (ModestMailOperation *self,
1604 gboolean remove_to_trash)
1606 TnyAccount *account;
1607 ModestMailOperationPrivate *priv;
1608 ModestTnyFolderRules rules;
1610 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1611 g_return_if_fail (TNY_IS_FOLDER (folder));
1613 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1615 /* Check folder rules */
1616 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1617 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1618 /* Set status failed and set an error */
1619 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1620 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1621 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1622 _("mail_in_ui_folder_delete_error"));
1626 /* Get the account */
1627 account = modest_tny_folder_get_account (folder);
1628 priv->account = g_object_ref(account);
1630 /* Delete folder or move to trash */
1631 if (remove_to_trash) {
1632 TnyFolder *trash_folder = NULL;
1633 trash_folder = modest_tny_account_get_special_folder (account,
1634 TNY_FOLDER_TYPE_TRASH);
1635 /* TODO: error_handling */
1637 modest_mail_operation_xfer_folder (self, folder,
1638 TNY_FOLDER_STORE (trash_folder),
1640 g_object_unref (trash_folder);
1643 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1645 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1646 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1649 g_object_unref (G_OBJECT (parent));
1651 g_object_unref (G_OBJECT (account));
1654 /* Notify about operation end */
1655 modest_mail_operation_notify_end (self);
1659 transfer_folder_status_cb (GObject *obj,
1663 ModestMailOperation *self;
1664 ModestMailOperationPrivate *priv;
1665 ModestMailOperationState *state;
1666 XFerMsgAsyncHelper *helper;
1668 g_return_if_fail (status != NULL);
1669 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1671 helper = (XFerMsgAsyncHelper *) user_data;
1672 g_return_if_fail (helper != NULL);
1674 self = helper->mail_op;
1675 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1677 priv->done = status->position;
1678 priv->total = status->of_total;
1680 state = modest_mail_operation_clone_state (self);
1682 /* This is not a GDK lock because we are a Tinymail callback
1683 * which is already GDK locked by Tinymail */
1685 /* no gdk_threads_enter (), CHECKED */
1687 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1689 /* no gdk_threads_leave (), CHECKED */
1691 g_slice_free (ModestMailOperationState, state);
1696 transfer_folder_cb (TnyFolder *folder, gboolean cancelled,
1697 TnyFolderStore *into,
1698 TnyFolder *new_folder,
1702 XFerMsgAsyncHelper *helper;
1703 ModestMailOperation *self = NULL;
1704 ModestMailOperationPrivate *priv = NULL;
1706 helper = (XFerMsgAsyncHelper *) user_data;
1707 g_return_if_fail (helper != NULL);
1709 self = helper->mail_op;
1710 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1713 priv->error = g_error_copy (err);
1715 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1716 } else if (cancelled) {
1717 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1718 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1719 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1720 _("Transference of %s was cancelled."),
1721 tny_folder_get_name (folder));
1724 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1727 /* Notify about operation end */
1728 modest_mail_operation_notify_end (self);
1730 /* If user defined callback function was defined, call it */
1731 if (helper->user_callback) {
1733 /* This is not a GDK lock because we are a Tinymail callback
1734 * which is already GDK locked by Tinymail */
1736 /* no gdk_threads_enter (), CHECKED */
1737 helper->user_callback (priv->source, helper->user_data);
1738 /* no gdk_threads_leave () , CHECKED */
1742 g_object_unref (helper->mail_op);
1743 g_slice_free (XFerMsgAsyncHelper, helper);
1748 * This function checks if the new name is a valid name for our local
1749 * folders account. The new name could not be the same than then name
1750 * of any of the mandatory local folders
1752 * We can not rely on tinymail because tinymail does not check the
1753 * name of the virtual folders that the account could have in the case
1754 * that we're doing a rename (because it directly calls Camel which
1755 * knows nothing about our virtual folders).
1757 * In the case of an actual copy/move (i.e. move/copy a folder between
1758 * accounts) tinymail uses the tny_folder_store_create_account which
1759 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1760 * checks the new name of the folder, so this call in that case
1761 * wouldn't be needed. *But* NOTE that if tinymail changes its
1762 * implementation (if folder transfers within the same account is no
1763 * longer implemented as a rename) this call will allow Modest to work
1766 * If the new name is not valid, this function will set the status to
1767 * failed and will set also an error in the mail operation
1770 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1771 TnyFolderStore *into,
1772 const gchar *new_name)
1774 if (TNY_IS_ACCOUNT (into) &&
1775 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1776 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1778 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1779 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1780 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1781 _("FIXME: folder name already in use"));
1788 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1790 TnyFolderStore *parent,
1791 gboolean delete_original,
1792 XferMsgsAsynUserCallback user_callback,
1795 ModestMailOperationPrivate *priv = NULL;
1796 ModestTnyFolderRules parent_rules = 0, rules;
1797 XFerMsgAsyncHelper *helper = NULL;
1799 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1800 g_return_if_fail (TNY_IS_FOLDER (folder));
1802 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1804 /* Get account and set it into mail_operation */
1805 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1806 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1808 /* Get folder rules */
1809 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1810 if (TNY_IS_FOLDER (parent))
1811 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1813 /* The moveable restriction is applied also to copy operation */
1814 if ((gpointer) parent == (gpointer) folder ||
1815 (!TNY_IS_FOLDER_STORE (parent)) ||
1816 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1817 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1818 /* Set status failed and set an error */
1819 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1820 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1821 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1822 _("mail_in_ui_folder_move_target_error"));
1824 /* Notify the queue */
1825 modest_mail_operation_notify_end (self);
1826 } else if (TNY_IS_FOLDER (parent) &&
1827 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1828 /* Set status failed and set an error */
1829 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1830 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1831 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1832 _("FIXME: parent folder does not accept new folders"));
1834 /* Notify the queue */
1835 modest_mail_operation_notify_end (self);
1839 /* Check that the new folder name is not used by any
1840 special local folder */
1841 if (new_name_valid_if_local_account (priv, parent,
1842 tny_folder_get_name (folder))) {
1843 /* Create the helper */
1844 helper = g_slice_new0 (XFerMsgAsyncHelper);
1845 helper->mail_op = g_object_ref(self);
1846 helper->dest_folder = NULL;
1847 helper->headers = NULL;
1848 helper->user_callback = user_callback;
1849 helper->user_data = user_data;
1851 /* Move/Copy folder */
1852 tny_folder_copy_async (folder,
1854 tny_folder_get_name (folder),
1857 transfer_folder_status_cb,
1860 modest_mail_operation_notify_end (self);
1866 modest_mail_operation_rename_folder (ModestMailOperation *self,
1870 ModestMailOperationPrivate *priv;
1871 ModestTnyFolderRules rules;
1872 XFerMsgAsyncHelper *helper;
1874 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1875 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1876 g_return_if_fail (name);
1878 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1880 /* Get account and set it into mail_operation */
1881 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1883 /* Check folder rules */
1884 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1885 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1886 /* Set status failed and set an error */
1887 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1888 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1889 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1890 _("FIXME: unable to rename"));
1892 /* Notify about operation end */
1893 modest_mail_operation_notify_end (self);
1894 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1895 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1896 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1897 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1898 _("FIXME: unable to rename"));
1899 /* Notify about operation end */
1900 modest_mail_operation_notify_end (self);
1902 TnyFolderStore *into;
1904 into = tny_folder_get_folder_store (folder);
1906 /* Check that the new folder name is not used by any
1907 special local folder */
1908 if (new_name_valid_if_local_account (priv, into, name)) {
1909 /* Create the helper */
1910 helper = g_slice_new0 (XFerMsgAsyncHelper);
1911 helper->mail_op = g_object_ref(self);
1912 helper->dest_folder = NULL;
1913 helper->headers = NULL;
1914 helper->user_callback = NULL;
1915 helper->user_data = NULL;
1917 /* Rename. Camel handles folder subscription/unsubscription */
1918 tny_folder_copy_async (folder, into, name, TRUE,
1920 transfer_folder_status_cb,
1923 modest_mail_operation_notify_end (self);
1925 g_object_unref (into);
1929 /* ******************************************************************* */
1930 /* ************************** MSG ACTIONS ************************* */
1931 /* ******************************************************************* */
1933 void modest_mail_operation_get_msg (ModestMailOperation *self,
1935 GetMsgAsyncUserCallback user_callback,
1938 GetMsgAsyncHelper *helper = NULL;
1940 ModestMailOperationPrivate *priv;
1942 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1943 g_return_if_fail (TNY_IS_HEADER (header));
1945 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1946 folder = tny_header_get_folder (header);
1948 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1950 /* Get message from folder */
1952 /* Get account and set it into mail_operation */
1953 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1955 /* Check for cached messages */
1956 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
1957 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1959 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1961 helper = g_slice_new0 (GetMsgAsyncHelper);
1962 helper->mail_op = self;
1963 helper->user_callback = user_callback;
1964 helper->user_data = user_data;
1965 helper->header = g_object_ref (header);
1967 // The callback's reference so that the mail op is not
1968 // finalized until the async operation is completed even if
1969 // the user canceled the request meanwhile.
1970 g_object_ref (G_OBJECT (helper->mail_op));
1972 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1974 g_object_unref (G_OBJECT (folder));
1976 /* Set status failed and set an error */
1977 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1978 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1979 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1980 _("Error trying to get a message. No folder found for header"));
1982 /* Notify the queue */
1983 modest_mail_operation_notify_end (self);
1988 get_msg_cb (TnyFolder *folder,
1994 GetMsgAsyncHelper *helper = NULL;
1995 ModestMailOperation *self = NULL;
1996 ModestMailOperationPrivate *priv = NULL;
1998 helper = (GetMsgAsyncHelper *) user_data;
1999 g_return_if_fail (helper != NULL);
2000 self = helper->mail_op;
2001 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2002 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2004 /* Check errors and cancel */
2006 priv->error = g_error_copy (error);
2007 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2008 } else if (cancelled) {
2009 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2010 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2011 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2012 _("Error trying to refresh the contents of %s"),
2013 tny_folder_get_name (folder));
2015 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2018 /* If user defined callback function was defined, call it even
2019 if the operation failed*/
2020 if (helper->user_callback) {
2021 /* This is not a GDK lock because we are a Tinymail callback
2022 * which is already GDK locked by Tinymail */
2024 /* no gdk_threads_enter (), CHECKED */
2025 helper->user_callback (self, helper->header, msg, helper->user_data);
2026 /* no gdk_threads_leave (), CHECKED */
2029 /* Notify about operation end */
2030 modest_mail_operation_notify_end (self);
2032 g_object_unref (helper->mail_op);
2033 g_object_unref (helper->header);
2034 g_slice_free (GetMsgAsyncHelper, helper);
2039 get_msg_status_cb (GObject *obj,
2043 GetMsgAsyncHelper *helper = NULL;
2044 ModestMailOperation *self;
2045 ModestMailOperationPrivate *priv;
2046 ModestMailOperationState *state;
2048 g_return_if_fail (status != NULL);
2049 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2051 helper = (GetMsgAsyncHelper *) user_data;
2052 g_return_if_fail (helper != NULL);
2054 self = helper->mail_op;
2055 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2060 state = modest_mail_operation_clone_state (self);
2061 state->bytes_done = status->position;
2062 state->bytes_total = status->of_total;
2064 /* This is not a GDK lock because we are a Tinymail callback
2065 * which is already GDK locked by Tinymail */
2067 /* no gdk_threads_enter (), CHECKED */
2068 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2069 /* no gdk_threads_leave (), CHECKED */
2071 g_slice_free (ModestMailOperationState, state);
2074 /****************************************************/
2076 ModestMailOperation *mail_op;
2078 GetMsgAsyncUserCallback user_callback;
2080 GDestroyNotify notify;
2084 GetMsgAsyncUserCallback user_callback;
2088 ModestMailOperation *mail_op;
2089 } NotifyGetMsgsInfo;
2093 * Used by get_msgs_full_thread to call the user_callback for each
2094 * message that has been read
2097 notify_get_msgs_full (gpointer data)
2099 NotifyGetMsgsInfo *info;
2101 info = (NotifyGetMsgsInfo *) data;
2103 /* This is a GDK lock because we are an idle callback and
2104 * because info->user_callback can contain Gtk+ code */
2106 gdk_threads_enter (); /* CHECKED */
2107 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2108 gdk_threads_leave (); /* CHECKED */
2110 g_slice_free (NotifyGetMsgsInfo, info);
2116 * Used by get_msgs_full_thread to free al the thread resources and to
2117 * call the destroy function for the passed user_data
2120 get_msgs_full_destroyer (gpointer data)
2122 GetFullMsgsInfo *info;
2124 info = (GetFullMsgsInfo *) data;
2128 /* This is a GDK lock because we are an idle callback and
2129 * because info->notify can contain Gtk+ code */
2131 gdk_threads_enter (); /* CHECKED */
2132 info->notify (info->user_data);
2133 gdk_threads_leave (); /* CHECKED */
2137 g_object_unref (info->headers);
2138 g_slice_free (GetFullMsgsInfo, info);
2144 get_msgs_full_thread (gpointer thr_user_data)
2146 GetFullMsgsInfo *info;
2147 ModestMailOperationPrivate *priv = NULL;
2148 TnyIterator *iter = NULL;
2150 info = (GetFullMsgsInfo *) thr_user_data;
2151 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2153 iter = tny_list_create_iterator (info->headers);
2154 while (!tny_iterator_is_done (iter)) {
2158 header = TNY_HEADER (tny_iterator_get_current (iter));
2159 folder = tny_header_get_folder (header);
2161 /* Check for cached messages */
2162 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2163 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2165 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2167 /* Get message from folder */
2170 /* The callback will call it per each header */
2171 msg = tny_folder_get_msg (folder, header, &(priv->error));
2174 ModestMailOperationState *state;
2179 /* notify progress */
2180 state = modest_mail_operation_clone_state (info->mail_op);
2181 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2182 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2183 pair, (GDestroyNotify) modest_pair_free);
2185 /* The callback is the responsible for
2186 freeing the message */
2187 if (info->user_callback) {
2188 NotifyGetMsgsInfo *info_notify;
2189 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2190 info_notify->user_callback = info->user_callback;
2191 info_notify->mail_op = info->mail_op;
2192 info_notify->header = g_object_ref (header);
2193 info_notify->msg = g_object_ref (msg);
2194 info_notify->user_data = info->user_data;
2195 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2196 notify_get_msgs_full,
2199 g_object_unref (msg);
2202 /* Set status failed and set an error */
2203 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2204 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2205 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2206 "Error trying to get a message. No folder found for header");
2210 g_object_unref (header);
2212 tny_iterator_next (iter);
2215 /* Set operation status */
2216 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2217 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2219 /* Notify about operation end */
2220 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2222 /* Free thread resources. Will be called after all previous idles */
2223 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2229 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2230 TnyList *header_list,
2231 GetMsgAsyncUserCallback user_callback,
2233 GDestroyNotify notify)
2235 TnyHeader *header = NULL;
2236 TnyFolder *folder = NULL;
2238 ModestMailOperationPrivate *priv = NULL;
2239 GetFullMsgsInfo *info = NULL;
2240 gboolean size_ok = TRUE;
2242 TnyIterator *iter = NULL;
2244 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2246 /* Init mail operation */
2247 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2248 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2250 priv->total = tny_list_get_length(header_list);
2252 /* Get account and set it into mail_operation */
2253 if (tny_list_get_length (header_list) >= 1) {
2254 iter = tny_list_create_iterator (header_list);
2255 header = TNY_HEADER (tny_iterator_get_current (iter));
2257 folder = tny_header_get_folder (header);
2259 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2261 g_object_unref (folder);
2264 g_object_unref (header);
2267 if (tny_list_get_length (header_list) == 1) {
2268 g_object_unref (iter);
2273 /* Get msg size limit */
2274 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2275 MODEST_CONF_MSG_SIZE_LIMIT,
2278 g_clear_error (&(priv->error));
2279 max_size = G_MAXINT;
2281 max_size = max_size * KB;
2284 /* Check message size limits. If there is only one message
2285 always retrieve it */
2287 while (!tny_iterator_is_done (iter) && size_ok) {
2288 header = TNY_HEADER (tny_iterator_get_current (iter));
2290 if (tny_header_get_message_size (header) >= max_size)
2292 g_object_unref (header);
2295 tny_iterator_next (iter);
2297 g_object_unref (iter);
2301 /* Create the info */
2302 info = g_slice_new0 (GetFullMsgsInfo);
2303 info->mail_op = self;
2304 info->user_callback = user_callback;
2305 info->user_data = user_data;
2306 info->headers = g_object_ref (header_list);
2307 info->notify = notify;
2309 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2311 /* Set status failed and set an error */
2312 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2313 /* FIXME: the error msg is different for pop */
2314 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2315 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2316 _("emev_ni_ui_imap_msg_size_exceed_error"));
2317 /* Remove from queue and free resources */
2318 modest_mail_operation_notify_end (self);
2326 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2327 gboolean remove_to_trash /*ignored*/)
2330 ModestMailOperationPrivate *priv;
2332 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2333 g_return_if_fail (TNY_IS_HEADER (header));
2335 if (remove_to_trash)
2336 g_warning ("remove to trash is not implemented");
2338 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2339 folder = tny_header_get_folder (header);
2341 /* Get account and set it into mail_operation */
2342 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2344 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2346 /* remove message from folder */
2347 tny_folder_remove_msg (folder, header, &(priv->error));
2348 /* if (!priv->error) { */
2349 /* tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED); */
2350 /* tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN); */
2352 /* if (TNY_IS_CAMEL_IMAP_FOLDER (folder)) */
2353 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* FALSE --> don't expunge *\/ */
2354 /* /\* tny_folder_sync (folder, FALSE, &(priv->error)); /\\* FALSE --> don't expunge *\\/ *\/ */
2355 /* else if (TNY_IS_CAMEL_POP_FOLDER (folder)) */
2356 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* TRUE --> dont expunge *\/ */
2357 /* /\* tny_folder_sync (folder, TRUE, &(priv->error)); /\\* TRUE --> expunge *\\/ *\/ */
2359 /* /\* local folders *\/ */
2360 /* tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /\* 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);
2403 /* This is not a GDK lock because we are a Tinymail callback and
2404 * Tinymail already acquires the Gdk lock */
2406 /* no gdk_threads_enter (), CHECKED */
2408 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2410 /* no gdk_threads_leave (), CHECKED */
2412 g_slice_free (ModestMailOperationState, state);
2417 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2419 XFerMsgAsyncHelper *helper;
2420 ModestMailOperation *self;
2421 ModestMailOperationPrivate *priv;
2422 TnyIterator *iter = NULL;
2423 TnyHeader *header = NULL;
2425 helper = (XFerMsgAsyncHelper *) user_data;
2426 self = helper->mail_op;
2428 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2431 priv->error = g_error_copy (err);
2433 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2434 } else if (cancelled) {
2435 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2436 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2437 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2438 _("Error trying to refresh the contents of %s"),
2439 tny_folder_get_name (folder));
2442 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2446 /* Mark headers as deleted and seen */
2447 if ((helper->delete) &&
2448 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2449 iter = tny_list_create_iterator (helper->headers);
2450 while (!tny_iterator_is_done (iter)) {
2451 header = TNY_HEADER (tny_iterator_get_current (iter));
2452 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2453 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2454 g_object_unref (header);
2456 tny_iterator_next (iter);
2462 /* Notify about operation end */
2463 modest_mail_operation_notify_end (self);
2465 /* If user defined callback function was defined, call it */
2466 if (helper->user_callback) {
2467 /* This is not a GDK lock because we are a Tinymail callback and
2468 * Tinymail already acquires the Gdk lock */
2470 /* no gdk_threads_enter (), CHECKED */
2471 helper->user_callback (priv->source, helper->user_data);
2472 /* no gdk_threads_leave (), CHECKED */
2476 if (helper->headers)
2477 g_object_unref (helper->headers);
2478 if (helper->dest_folder)
2479 g_object_unref (helper->dest_folder);
2480 if (helper->mail_op)
2481 g_object_unref (helper->mail_op);
2483 g_object_unref (folder);
2485 g_object_unref (iter);
2486 g_slice_free (XFerMsgAsyncHelper, helper);
2491 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2494 gboolean delete_original,
2495 XferMsgsAsynUserCallback user_callback,
2498 ModestMailOperationPrivate *priv = NULL;
2499 TnyIterator *iter = NULL;
2500 TnyFolder *src_folder = NULL;
2501 XFerMsgAsyncHelper *helper = NULL;
2502 TnyHeader *header = NULL;
2503 ModestTnyFolderRules rules = 0;
2504 const gchar *id1 = NULL;
2505 const gchar *id2 = NULL;
2506 gboolean same_folder = FALSE;
2508 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2509 g_return_if_fail (TNY_IS_LIST (headers));
2510 g_return_if_fail (TNY_IS_FOLDER (folder));
2512 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2515 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2517 /* Apply folder rules */
2518 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2519 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2520 /* Set status failed and set an error */
2521 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2522 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2523 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2524 _CS("ckct_ib_unable_to_paste_here"));
2525 /* Notify the queue */
2526 modest_mail_operation_notify_end (self);
2530 /* Get source folder */
2531 iter = tny_list_create_iterator (headers);
2532 header = TNY_HEADER (tny_iterator_get_current (iter));
2534 src_folder = tny_header_get_folder (header);
2535 g_object_unref (header);
2538 g_object_unref (iter);
2540 /* Check folder source and destination */
2541 id1 = tny_folder_get_id (src_folder);
2542 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2543 same_folder = !g_ascii_strcasecmp (id1, id2);
2545 /* Set status failed and set an error */
2546 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2547 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2548 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2549 _("mcen_ib_unable_to_copy_samefolder"));
2551 /* Notify the queue */
2552 modest_mail_operation_notify_end (self);
2555 g_object_unref (src_folder);
2559 /* Create the helper */
2560 helper = g_slice_new0 (XFerMsgAsyncHelper);
2561 helper->mail_op = g_object_ref(self);
2562 helper->dest_folder = g_object_ref(folder);
2563 helper->headers = g_object_ref(headers);
2564 helper->user_callback = user_callback;
2565 helper->user_data = user_data;
2566 helper->delete = delete_original;
2568 /* Get account and set it into mail_operation */
2569 priv->account = modest_tny_folder_get_account (src_folder);
2571 /* Transfer messages */
2572 tny_folder_transfer_msgs_async (src_folder,
2577 transfer_msgs_status_cb,
2583 on_refresh_folder (TnyFolder *folder,
2588 RefreshAsyncHelper *helper = NULL;
2589 ModestMailOperation *self = NULL;
2590 ModestMailOperationPrivate *priv = NULL;
2592 helper = (RefreshAsyncHelper *) user_data;
2593 self = helper->mail_op;
2594 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2596 g_return_if_fail(priv!=NULL);
2599 priv->error = g_error_copy (error);
2600 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2601 printf("DEBUG: %s: Operation error:\n %s", __FUNCTION__,
2607 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2608 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2609 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2610 _("Error trying to refresh the contents of %s"),
2611 tny_folder_get_name (folder));
2612 printf("DEBUG: %s: Operation cancelled.\n", __FUNCTION__);
2616 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2618 /* Call user defined callback, if it exists */
2619 if (helper->user_callback) {
2621 /* This is not a GDK lock because we are a Tinymail callback and
2622 * Tinymail already acquires the Gdk lock */
2624 /* no gdk_threads_enter (), CHECKED */
2625 helper->user_callback (self, folder, helper->user_data);
2626 /* no gdk_threads_leave (), CHECKED */
2631 g_slice_free (RefreshAsyncHelper, helper);
2633 /* Notify about operation end */
2634 modest_mail_operation_notify_end (self);
2635 g_object_unref(self);
2639 on_refresh_folder_status_update (GObject *obj,
2643 RefreshAsyncHelper *helper = NULL;
2644 ModestMailOperation *self = NULL;
2645 ModestMailOperationPrivate *priv = NULL;
2646 ModestMailOperationState *state;
2648 g_return_if_fail (user_data != NULL);
2649 g_return_if_fail (status != NULL);
2650 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2652 helper = (RefreshAsyncHelper *) user_data;
2653 self = helper->mail_op;
2654 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2656 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2658 priv->done = status->position;
2659 priv->total = status->of_total;
2661 state = modest_mail_operation_clone_state (self);
2663 /* This is not a GDK lock because we are a Tinymail callback and
2664 * Tinymail already acquires the Gdk lock */
2666 /* no gdk_threads_enter (), CHECKED */
2668 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2670 /* no gdk_threads_leave (), CHECKED */
2672 g_slice_free (ModestMailOperationState, state);
2676 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2678 RefreshAsyncUserCallback user_callback,
2681 ModestMailOperationPrivate *priv = NULL;
2682 RefreshAsyncHelper *helper = NULL;
2684 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2686 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2688 /* Get account and set it into mail_operation */
2689 priv->account = modest_tny_folder_get_account (folder);
2691 /* Create the helper */
2692 helper = g_slice_new0 (RefreshAsyncHelper);
2693 helper->mail_op = g_object_ref(self);
2694 helper->user_callback = user_callback;
2695 helper->user_data = user_data;
2697 /* Refresh the folder. TODO: tinymail could issue a status
2698 updates before the callback call then this could happen. We
2699 must review the design */
2700 tny_folder_refresh_async (folder,
2702 on_refresh_folder_status_update,
2708 * It's used by the mail operation queue to notify the observers
2709 * attached to that signal that the operation finished. We need to use
2710 * that because tinymail does not give us the progress of a given
2711 * operation when it finishes (it directly calls the operation
2715 modest_mail_operation_notify_end (ModestMailOperation *self)
2717 ModestMailOperationState *state;
2718 ModestMailOperationPrivate *priv = NULL;
2720 g_return_if_fail (self);
2722 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2724 /* Set the account back to not busy */
2725 if (priv->account_name) {
2726 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2727 priv->account_name, FALSE);
2728 g_free(priv->account_name);
2729 priv->account_name = NULL;
2732 /* Notify the observers about the mail operation end */
2733 /* We do not wrapp this emission because we assume that this
2734 function is always called from within the main lock */
2735 state = modest_mail_operation_clone_state (self);
2736 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2737 g_slice_free (ModestMailOperationState, state);