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 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 gdk_threads_enter ();
579 info->callback (info->mail_op, info->msg, info->userdata);
580 gdk_threads_leave ();
581 g_object_unref (info->mail_op);
583 g_object_unref (info->msg);
584 g_slice_free (CreateMsgIdleInfo, info);
590 create_msg_thread (gpointer thread_data)
592 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
593 TnyMsg *new_msg = NULL;
594 ModestMailOperationPrivate *priv;
596 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
597 if (info->html_body == NULL) {
598 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
599 info->bcc, info->subject, info->plain_body,
600 info->attachments_list); /* FIXME: attachments */
602 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
603 info->bcc, info->subject, info->html_body,
604 info->plain_body, info->attachments_list);
609 /* Set priority flags in message */
610 header = tny_msg_get_header (new_msg);
611 if (info->priority_flags != 0)
612 tny_header_set_flags (header, info->priority_flags);
613 if (info->attachments_list != NULL) {
614 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
616 g_object_unref (G_OBJECT(header));
618 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
619 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
620 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
621 "modest: failed to create a new msg\n");
629 g_free (info->plain_body);
630 g_free (info->html_body);
631 g_free (info->subject);
632 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
633 g_list_free (info->attachments_list);
635 if (info->callback) {
636 CreateMsgIdleInfo *idle_info;
637 idle_info = g_slice_new0 (CreateMsgIdleInfo);
638 idle_info->mail_op = info->mail_op;
639 g_object_ref (info->mail_op);
640 idle_info->msg = new_msg;
642 g_object_ref (new_msg);
643 idle_info->callback = info->callback;
644 idle_info->userdata = info->userdata;
645 g_idle_add (idle_create_msg_cb, idle_info);
647 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
650 g_object_unref (info->mail_op);
651 g_slice_free (CreateMsgInfo, info);
656 modest_mail_operation_create_msg (ModestMailOperation *self,
657 const gchar *from, const gchar *to,
658 const gchar *cc, const gchar *bcc,
659 const gchar *subject, const gchar *plain_body,
660 const gchar *html_body,
661 const GList *attachments_list,
662 TnyHeaderFlags priority_flags,
663 ModestMailOperationCreateMsgCallback callback,
666 CreateMsgInfo *info = NULL;
668 info = g_slice_new0 (CreateMsgInfo);
669 info->mail_op = self;
672 info->from = g_strdup (from);
673 info->to = g_strdup (to);
674 info->cc = g_strdup (cc);
675 info->bcc = g_strdup (bcc);
676 info->subject = g_strdup (subject);
677 info->plain_body = g_strdup (plain_body);
678 info->html_body = g_strdup (html_body);
679 info->attachments_list = g_list_copy ((GList *) attachments_list);
680 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
681 info->priority_flags = priority_flags;
683 info->callback = callback;
684 info->userdata = userdata;
686 g_thread_create (create_msg_thread, info, FALSE, NULL);
691 TnyTransportAccount *transport_account;
696 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
700 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
701 TnyFolder *draft_folder = NULL;
702 TnyFolder *outbox_folder = NULL;
709 /* Call mail operation */
710 modest_mail_operation_send_mail (self, info->transport_account, msg);
712 /* Remove old mail from its source folder */
713 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
714 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_OUTBOX);
715 if (info->draft_msg != NULL) {
716 TnyFolder *folder = NULL;
717 TnyFolder *src_folder = NULL;
718 TnyFolderType folder_type;
719 folder = tny_msg_get_folder (info->draft_msg);
720 if (folder == NULL) goto end;
721 folder_type = modest_tny_folder_guess_folder_type (folder);
722 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
723 src_folder = outbox_folder;
725 src_folder = draft_folder;
727 /* Note: This can fail (with a warning) if the message is not really already in a folder,
728 * because this function requires it to have a UID. */
729 header = tny_msg_get_header (info->draft_msg);
730 tny_folder_remove_msg (src_folder, header, NULL);
731 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
732 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
733 g_object_unref (header);
734 g_object_unref (folder);
739 g_object_unref (info->draft_msg);
741 g_object_unref (draft_folder);
743 g_object_unref (outbox_folder);
744 if (info->transport_account)
745 g_object_unref (info->transport_account);
746 g_slice_free (SendNewMailInfo, info);
747 modest_mail_operation_notify_end (self);
751 modest_mail_operation_send_new_mail (ModestMailOperation *self,
752 TnyTransportAccount *transport_account,
754 const gchar *from, const gchar *to,
755 const gchar *cc, const gchar *bcc,
756 const gchar *subject, const gchar *plain_body,
757 const gchar *html_body,
758 const GList *attachments_list,
759 TnyHeaderFlags priority_flags)
761 ModestMailOperationPrivate *priv = NULL;
762 SendNewMailInfo *info;
764 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
765 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
767 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
769 /* Check parametters */
771 /* Set status failed and set an error */
772 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
773 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
774 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
775 _("Error trying to send a mail. You need to set at least one recipient"));
778 info = g_slice_new0 (SendNewMailInfo);
779 info->transport_account = transport_account;
780 if (transport_account)
781 g_object_ref (transport_account);
782 info->draft_msg = draft_msg;
784 g_object_ref (draft_msg);
785 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
786 attachments_list, priority_flags,
787 modest_mail_operation_send_new_mail_cb, info);
793 TnyTransportAccount *transport_account;
795 ModestMsgEditWindow *edit_window;
799 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
803 TnyFolder *src_folder = NULL;
804 TnyFolder *folder = NULL;
805 TnyHeader *header = NULL;
806 ModestMailOperationPrivate *priv = NULL;
807 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
809 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
811 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
812 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
813 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
814 "modest: failed to create a new msg\n");
818 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
820 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
821 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
822 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
823 "modest: failed to create a new msg\n");
827 if (info->draft_msg != NULL) {
828 header = tny_msg_get_header (info->draft_msg);
829 src_folder = tny_header_get_folder (header);
830 /* Remove the old draft expunging it */
831 tny_folder_remove_msg (src_folder, header, NULL);
832 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
833 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
834 tny_folder_sync (src_folder, TRUE, &(priv->error)); /* expunge */
835 g_object_unref (header);
839 tny_folder_add_msg (folder, msg, &(priv->error));
842 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
844 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
846 if (info->edit_window)
847 modest_msg_edit_window_set_draft (info->edit_window, msg);
852 g_object_unref (G_OBJECT(folder));
854 g_object_unref (G_OBJECT(src_folder));
855 if (info->edit_window)
856 g_object_unref (G_OBJECT(info->edit_window));
858 g_object_unref (G_OBJECT (info->draft_msg));
859 if (info->transport_account)
860 g_object_unref (G_OBJECT(info->transport_account));
861 g_slice_free (SaveToDraftsInfo, info);
863 modest_mail_operation_notify_end (self);
867 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
868 TnyTransportAccount *transport_account,
870 ModestMsgEditWindow *edit_window,
871 const gchar *from, const gchar *to,
872 const gchar *cc, const gchar *bcc,
873 const gchar *subject, const gchar *plain_body,
874 const gchar *html_body,
875 const GList *attachments_list,
876 TnyHeaderFlags priority_flags)
878 ModestMailOperationPrivate *priv = NULL;
879 SaveToDraftsInfo *info = NULL;
881 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
882 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
884 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
886 /* Get account and set it into mail_operation */
887 priv->account = g_object_ref (transport_account);
889 info = g_slice_new0 (SaveToDraftsInfo);
890 info->transport_account = g_object_ref (transport_account);
891 info->draft_msg = draft_msg;
893 g_object_ref (draft_msg);
894 info->edit_window = edit_window;
896 g_object_ref (edit_window);
898 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
899 attachments_list, priority_flags,
900 modest_mail_operation_save_to_drafts_cb, info);
906 ModestMailOperation *mail_op;
907 TnyStoreAccount *account;
908 TnyTransportAccount *transport_account;
911 gchar *retrieve_type;
913 UpdateAccountCallback callback;
920 ModestMailOperation *mail_op;
921 TnyMimePart *mime_part;
923 GetMimePartSizeCallback callback;
925 } GetMimePartSizeInfo;
927 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
928 /* We use this folder observer to track the headers that have been
929 * added to a folder */
932 TnyList *new_headers;
933 } InternalFolderObserver;
937 } InternalFolderObserverClass;
939 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
941 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
942 internal_folder_observer,
944 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
948 foreach_add_item (gpointer header, gpointer user_data)
950 tny_list_prepend (TNY_LIST (user_data),
951 g_object_ref (G_OBJECT (header)));
954 /* This is the method that looks for new messages in a folder */
956 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
958 InternalFolderObserver *derived = (InternalFolderObserver *)self;
960 TnyFolderChangeChanged changed;
962 changed = tny_folder_change_get_changed (change);
964 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
967 /* Get added headers */
968 list = tny_simple_list_new ();
969 tny_folder_change_get_added_headers (change, list);
971 /* Add them to the folder observer */
972 tny_list_foreach (list, foreach_add_item,
973 derived->new_headers);
975 g_object_unref (G_OBJECT (list));
980 internal_folder_observer_init (InternalFolderObserver *self)
982 self->new_headers = tny_simple_list_new ();
985 internal_folder_observer_finalize (GObject *object)
987 InternalFolderObserver *self;
989 self = (InternalFolderObserver *) object;
990 g_object_unref (self->new_headers);
992 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
995 tny_folder_observer_init (TnyFolderObserverIface *iface)
997 iface->update_func = internal_folder_observer_update;
1000 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1002 GObjectClass *object_class;
1004 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1005 object_class = (GObjectClass*) klass;
1006 object_class->finalize = internal_folder_observer_finalize;
1012 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
1015 TnyList *folders = tny_simple_list_new ();
1017 tny_folder_store_get_folders (store, folders, query, NULL);
1018 iter = tny_list_create_iterator (folders);
1020 while (!tny_iterator_is_done (iter)) {
1022 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1024 tny_list_prepend (all_folders, G_OBJECT (folder));
1025 recurse_folders (folder, query, all_folders);
1026 g_object_unref (G_OBJECT (folder));
1029 tny_iterator_next (iter);
1031 g_object_unref (G_OBJECT (iter));
1032 g_object_unref (G_OBJECT (folders));
1036 * Issues the "progress-changed" signal. The timer won't be removed,
1037 * so you must call g_source_remove to stop the signal emission
1040 idle_notify_progress (gpointer data)
1042 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1043 ModestMailOperationState *state;
1045 state = modest_mail_operation_clone_state (mail_op);
1046 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1047 gdk_threads_enter ();
1049 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1050 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1051 gdk_threads_leave ();
1053 g_slice_free (ModestMailOperationState, state);
1059 * Issues the "progress-changed" signal and removes the timer. It uses
1060 * a lock to ensure that the progress information of the mail
1061 * operation is not modified while there are notifications pending
1064 idle_notify_progress_once (gpointer data)
1068 pair = (ModestPair *) data;
1070 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1071 gdk_threads_enter ();
1073 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1074 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1075 gdk_threads_leave ();
1078 /* Free the state and the reference to the mail operation */
1079 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1080 g_object_unref (pair->first);
1086 * Used to notify the queue from the main
1087 * loop. We call it inside an idle call to achieve that
1090 idle_notify_queue (gpointer data)
1092 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1094 /* Do not need to block, the notify end will do it for us */
1095 modest_mail_operation_notify_end (mail_op);
1096 g_object_unref (mail_op);
1102 compare_headers_by_date (gconstpointer a,
1105 TnyHeader **header1, **header2;
1106 time_t sent1, sent2;
1108 header1 = (TnyHeader **) a;
1109 header2 = (TnyHeader **) b;
1111 sent1 = tny_header_get_date_sent (*header1);
1112 sent2 = tny_header_get_date_sent (*header2);
1114 /* We want the most recent ones (greater time_t) at the
1123 set_last_updated_idle (gpointer data)
1125 gdk_threads_enter ();
1127 /* It does not matter if the time is not exactly the same than
1128 the time when this idle was called, it's just an
1129 approximation and it won't be very different */
1130 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1132 MODEST_ACCOUNT_LAST_UPDATED,
1136 gdk_threads_leave ();
1142 idle_update_account_cb (gpointer data)
1144 UpdateAccountInfo *idle_info;
1146 idle_info = (UpdateAccountInfo *) data;
1148 gdk_threads_enter ();
1149 idle_info->callback (idle_info->mail_op,
1150 idle_info->new_headers,
1151 idle_info->user_data);
1152 gdk_threads_leave ();
1155 g_object_unref (idle_info->mail_op);
1163 update_account_thread (gpointer thr_user_data)
1165 static gboolean first_time = TRUE;
1166 UpdateAccountInfo *info = NULL;
1167 TnyList *all_folders = NULL;
1168 GPtrArray *new_headers = NULL;
1169 TnyIterator *iter = NULL;
1170 TnyFolderStoreQuery *query = NULL;
1171 ModestMailOperationPrivate *priv = NULL;
1172 ModestTnySendQueue *send_queue = NULL;
1173 gint num_new_headers = 0;
1175 info = (UpdateAccountInfo *) thr_user_data;
1176 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1178 /* Get account and set it into mail_operation */
1179 priv->account = g_object_ref (info->account);
1182 * Previousl, we did this for POP3, to do a logout-login upon send/receive,
1183 * because many POP-servers (like Gmail) do not
1184 * show any updates unless we do that.
1185 * But that didn't work with gmail anyway,
1186 * and tinymail now takes care of this itself by disconnecting
1187 * automatically after using the connection.
1190 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT (priv->account))
1191 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1194 /* Get all the folders. We can do it synchronously because
1195 we're already running in a different thread than the UI */
1196 all_folders = tny_simple_list_new ();
1197 query = tny_folder_store_query_new ();
1198 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1199 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1204 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1208 iter = tny_list_create_iterator (all_folders);
1209 while (!tny_iterator_is_done (iter)) {
1210 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1212 recurse_folders (folder, query, all_folders);
1213 g_object_unref (folder);
1215 tny_iterator_next (iter);
1217 g_object_unref (G_OBJECT (iter));
1219 /* Update status and notify. We need to call the notification
1220 with a source function in order to call it from the main
1221 loop. We need that in order not to get into trouble with
1222 Gtk+. We use a timeout in order to provide more status
1223 information, because the sync tinymail call does not
1224 provide it for the moment */
1225 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1227 /* Refresh folders */
1228 num_new_headers = 0;
1229 new_headers = g_ptr_array_new ();
1230 iter = tny_list_create_iterator (all_folders);
1232 while (!tny_iterator_is_done (iter) && !priv->error &&
1233 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1235 InternalFolderObserver *observer;
1236 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1238 /* Refresh the folder */
1239 /* Our observer receives notification of new emails during folder refreshes,
1240 * so we can use observer->new_headers.
1242 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1243 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1245 /* This gets the status information (headers) from the server.
1246 * We use the blocking version, because we are already in a separate
1250 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1251 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1254 /* If the retrieve type is full messages, refresh and get the messages */
1255 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1257 iter = tny_list_create_iterator (observer->new_headers);
1258 while (!tny_iterator_is_done (iter)) {
1259 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1261 /* Apply per-message size limits */
1262 if (tny_header_get_message_size (header) < info->max_size)
1263 g_ptr_array_add (new_headers, g_object_ref (header));
1265 g_object_unref (header);
1266 tny_iterator_next (iter);
1268 g_object_unref (iter);
1270 /* We do not need to do it the first time
1271 because it's automatically done by the tree
1273 if (G_UNLIKELY (!first_time))
1274 tny_folder_poke_status (TNY_FOLDER (folder));
1276 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1277 g_object_unref (observer);
1281 g_object_unref (G_OBJECT (folder));
1284 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1286 tny_iterator_next (iter);
1289 g_object_unref (G_OBJECT (iter));
1290 g_source_remove (timeout);
1292 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1293 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1294 new_headers->len > 0) {
1298 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1300 /* Apply message count limit */
1301 /* If the number of messages exceeds the maximum, ask the
1302 * user to download them all,
1303 * as per the UI spec "Retrieval Limits" section in 4.4:
1305 if (new_headers->len > info->retrieve_limit) {
1306 /* TODO: Ask the user, instead of just
1308 * mail_nc_msg_count_limit_exceeded, with 'Get
1309 * all' and 'Newest only' buttons. */
1310 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1311 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1312 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1313 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1314 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1319 priv->total = MIN (new_headers->len, info->retrieve_limit);
1320 while (msg_num < priv->total) {
1322 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1323 TnyFolder *folder = tny_header_get_folder (header);
1324 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1325 ModestMailOperationState *state;
1329 /* We can not just use the mail operation because the
1330 values of done and total could change before the
1332 state = modest_mail_operation_clone_state (info->mail_op);
1333 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1334 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1335 pair, (GDestroyNotify) modest_pair_free);
1337 g_object_unref (msg);
1338 g_object_unref (folder);
1344 /* Get the number of new headers and free them */
1345 num_new_headers = new_headers->len;
1346 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1347 g_ptr_array_free (new_headers, FALSE);
1349 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1352 /* Perform send (if operation was not cancelled) */
1353 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1356 if (priv->account != NULL)
1357 g_object_unref (priv->account);
1358 priv->account = g_object_ref (info->transport_account);
1360 send_queue = modest_runtime_get_send_queue (info->transport_account);
1362 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1363 modest_tny_send_queue_try_to_send (send_queue);
1364 /* g_source_remove (timeout); */
1366 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1367 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1368 "cannot create a send queue for %s\n",
1369 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1370 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1373 /* Check if the operation was a success */
1375 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1377 /* Update the last updated key */
1378 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1379 set_last_updated_idle,
1380 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1381 (GDestroyNotify) g_free);
1386 if (info->callback) {
1387 UpdateAccountInfo *idle_info;
1389 /* This thread is not in the main lock */
1390 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1391 idle_info->mail_op = g_object_ref (info->mail_op);
1392 idle_info->new_headers = num_new_headers;
1393 idle_info->callback = info->callback;
1394 g_idle_add (idle_update_account_cb, idle_info);
1397 /* Notify about operation end. Note that the info could be
1398 freed before this idle happens, but the mail operation will
1400 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1403 g_object_unref (query);
1404 g_object_unref (all_folders);
1405 g_object_unref (info->account);
1406 g_object_unref (info->transport_account);
1407 g_free (info->retrieve_type);
1408 g_slice_free (UpdateAccountInfo, info);
1416 modest_mail_operation_update_account (ModestMailOperation *self,
1417 const gchar *account_name,
1418 UpdateAccountCallback callback,
1421 GThread *thread = NULL;
1422 UpdateAccountInfo *info = NULL;
1423 ModestMailOperationPrivate *priv = NULL;
1424 ModestAccountMgr *mgr = NULL;
1425 TnyStoreAccount *store_account = NULL;
1426 TnyTransportAccount *transport_account = NULL;
1428 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1429 g_return_val_if_fail (account_name, FALSE);
1431 /* Init mail operation. Set total and done to 0, and do not
1432 update them, this way the progress objects will know that
1433 we have no clue about the number of the objects */
1434 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1437 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1439 /* Get the Modest account */
1440 store_account = (TnyStoreAccount *)
1441 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1443 TNY_ACCOUNT_TYPE_STORE);
1445 /* Make sure that we have a connection, and request one
1447 * TODO: Is there some way to trigger this for every attempt to
1448 * use the network? */
1449 if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
1452 if (!store_account) {
1453 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1454 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1455 "cannot get tny store account for %s\n", account_name);
1460 /* Get the transport account, we can not do it in the thread
1461 due to some problems with dbus */
1462 transport_account = (TnyTransportAccount *)
1463 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1465 if (!transport_account) {
1466 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1467 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1468 "cannot get tny transport account for %s\n", account_name);
1472 /* Create the helper object */
1473 info = g_slice_new (UpdateAccountInfo);
1474 info->mail_op = self;
1475 info->account = store_account;
1476 info->transport_account = transport_account;
1477 info->callback = callback;
1478 info->user_data = user_data;
1480 /* Get the message size limit */
1481 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1482 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1483 if (info->max_size == 0)
1484 info->max_size = G_MAXINT;
1486 info->max_size = info->max_size * KB;
1488 /* Get per-account retrieval type */
1489 mgr = modest_runtime_get_account_mgr ();
1490 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1491 MODEST_ACCOUNT_RETRIEVE, FALSE);
1493 /* Get per-account message amount retrieval limit */
1494 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1495 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1496 if (info->retrieve_limit == 0)
1497 info->retrieve_limit = G_MAXINT;
1499 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1501 /* Set account busy */
1502 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1503 priv->account_name = g_strdup(account_name);
1505 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1510 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1512 callback (self, 0, user_data);
1513 modest_mail_operation_notify_end (self);
1517 /* ******************************************************************* */
1518 /* ************************** STORE ACTIONS ************************* */
1519 /* ******************************************************************* */
1523 modest_mail_operation_create_folder (ModestMailOperation *self,
1524 TnyFolderStore *parent,
1527 ModestMailOperationPrivate *priv;
1528 TnyFolder *new_folder = NULL;
1530 TnyList *list = tny_simple_list_new ();
1531 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1533 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1534 g_return_val_if_fail (name, NULL);
1536 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1538 /* Check for already existing folder */
1539 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1540 tny_folder_store_get_folders (parent, list, query, NULL);
1541 g_object_unref (G_OBJECT (query));
1543 if (tny_list_get_length (list) > 0) {
1544 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1545 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1546 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1547 _CS("ckdg_ib_folder_already_exists"));
1550 g_object_unref (G_OBJECT (list));
1553 if (TNY_IS_FOLDER (parent)) {
1554 /* Check folder rules */
1555 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1556 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1557 /* Set status failed and set an error */
1558 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1559 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1560 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1561 _("mail_in_ui_folder_create_error"));
1565 if (!strcmp (name, " ") || strchr (name, '/')) {
1566 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1567 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1568 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1569 _("mail_in_ui_folder_create_error"));
1573 /* Create the folder */
1574 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1575 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1577 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1580 /* Notify about operation end */
1581 modest_mail_operation_notify_end (self);
1587 modest_mail_operation_remove_folder (ModestMailOperation *self,
1589 gboolean remove_to_trash)
1591 TnyAccount *account;
1592 ModestMailOperationPrivate *priv;
1593 ModestTnyFolderRules rules;
1595 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1596 g_return_if_fail (TNY_IS_FOLDER (folder));
1598 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1600 /* Check folder rules */
1601 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1602 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1603 /* Set status failed and set an error */
1604 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1605 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1606 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1607 _("mail_in_ui_folder_delete_error"));
1611 /* Get the account */
1612 account = modest_tny_folder_get_account (folder);
1613 priv->account = g_object_ref(account);
1615 /* Delete folder or move to trash */
1616 if (remove_to_trash) {
1617 TnyFolder *trash_folder = NULL;
1618 trash_folder = modest_tny_account_get_special_folder (account,
1619 TNY_FOLDER_TYPE_TRASH);
1620 /* TODO: error_handling */
1622 modest_mail_operation_xfer_folder (self, folder,
1623 TNY_FOLDER_STORE (trash_folder),
1625 g_object_unref (trash_folder);
1628 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1630 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1631 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1634 g_object_unref (G_OBJECT (parent));
1636 g_object_unref (G_OBJECT (account));
1639 /* Notify about operation end */
1640 modest_mail_operation_notify_end (self);
1644 transfer_folder_status_cb (GObject *obj,
1648 ModestMailOperation *self;
1649 ModestMailOperationPrivate *priv;
1650 ModestMailOperationState *state;
1651 XFerMsgAsyncHelper *helper;
1653 g_return_if_fail (status != NULL);
1654 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1656 helper = (XFerMsgAsyncHelper *) user_data;
1657 g_return_if_fail (helper != NULL);
1659 self = helper->mail_op;
1660 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1662 priv->done = status->position;
1663 priv->total = status->of_total;
1665 state = modest_mail_operation_clone_state (self);
1666 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1667 gdk_threads_enter ();
1669 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1670 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1671 gdk_threads_leave ();
1673 g_slice_free (ModestMailOperationState, state);
1678 transfer_folder_cb (TnyFolder *folder,
1679 TnyFolderStore *into,
1681 TnyFolder *new_folder,
1685 XFerMsgAsyncHelper *helper;
1686 ModestMailOperation *self = NULL;
1687 ModestMailOperationPrivate *priv = NULL;
1689 helper = (XFerMsgAsyncHelper *) user_data;
1690 g_return_if_fail (helper != NULL);
1692 self = helper->mail_op;
1693 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1696 priv->error = g_error_copy (*err);
1698 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1699 } else if (cancelled) {
1700 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1701 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1702 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1703 _("Transference of %s was cancelled."),
1704 tny_folder_get_name (folder));
1707 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1710 /* Notify about operation end */
1711 modest_mail_operation_notify_end (self);
1713 /* If user defined callback function was defined, call it */
1714 if (helper->user_callback) {
1715 gdk_threads_enter ();
1716 helper->user_callback (priv->source, helper->user_data);
1717 gdk_threads_leave ();
1721 g_object_unref (helper->mail_op);
1722 g_slice_free (XFerMsgAsyncHelper, helper);
1727 * This function checks if the new name is a valid name for our local
1728 * folders account. The new name could not be the same than then name
1729 * of any of the mandatory local folders
1731 * We can not rely on tinymail because tinymail does not check the
1732 * name of the virtual folders that the account could have in the case
1733 * that we're doing a rename (because it directly calls Camel which
1734 * knows nothing about our virtual folders).
1736 * In the case of an actual copy/move (i.e. move/copy a folder between
1737 * accounts) tinymail uses the tny_folder_store_create_account which
1738 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1739 * checks the new name of the folder, so this call in that case
1740 * wouldn't be needed. *But* NOTE that if tinymail changes its
1741 * implementation (if folder transfers within the same account is no
1742 * longer implemented as a rename) this call will allow Modest to work
1745 * If the new name is not valid, this function will set the status to
1746 * failed and will set also an error in the mail operation
1749 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1750 TnyFolderStore *into,
1751 const gchar *new_name)
1753 if (TNY_IS_ACCOUNT (into) &&
1754 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1755 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1757 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1758 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1759 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1760 _("FIXME: folder name already in use"));
1767 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1769 TnyFolderStore *parent,
1770 gboolean delete_original,
1771 XferMsgsAsynUserCallback user_callback,
1774 ModestMailOperationPrivate *priv = NULL;
1775 ModestTnyFolderRules parent_rules = 0, rules;
1776 XFerMsgAsyncHelper *helper = NULL;
1778 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1779 g_return_if_fail (TNY_IS_FOLDER (folder));
1781 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1783 /* Get account and set it into mail_operation */
1784 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1785 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1787 /* Get folder rules */
1788 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1789 if (TNY_IS_FOLDER (parent))
1790 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1792 /* The moveable restriction is applied also to copy operation */
1793 if ((gpointer) parent == (gpointer) folder ||
1794 (!TNY_IS_FOLDER_STORE (parent)) ||
1795 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1796 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1797 /* Set status failed and set an error */
1798 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1799 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1800 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1801 _("mail_in_ui_folder_move_target_error"));
1803 /* Notify the queue */
1804 modest_mail_operation_notify_end (self);
1805 } else if (TNY_IS_FOLDER (parent) &&
1806 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1807 /* Set status failed and set an error */
1808 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1809 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1810 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1811 _("FIXME: parent folder does not accept new folders"));
1813 /* Notify the queue */
1814 modest_mail_operation_notify_end (self);
1818 /* Check that the new folder name is not used by any
1819 special local folder */
1820 if (new_name_valid_if_local_account (priv, parent,
1821 tny_folder_get_name (folder))) {
1822 /* Create the helper */
1823 helper = g_slice_new0 (XFerMsgAsyncHelper);
1824 helper->mail_op = g_object_ref(self);
1825 helper->dest_folder = NULL;
1826 helper->headers = NULL;
1827 helper->user_callback = user_callback;
1828 helper->user_data = user_data;
1830 /* Move/Copy folder */
1831 tny_folder_copy_async (folder,
1833 tny_folder_get_name (folder),
1836 transfer_folder_status_cb,
1839 modest_mail_operation_notify_end (self);
1845 modest_mail_operation_rename_folder (ModestMailOperation *self,
1849 ModestMailOperationPrivate *priv;
1850 ModestTnyFolderRules rules;
1851 XFerMsgAsyncHelper *helper;
1853 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1854 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1855 g_return_if_fail (name);
1857 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1859 /* Get account and set it into mail_operation */
1860 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1862 /* Check folder rules */
1863 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1864 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1865 /* Set status failed and set an error */
1866 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1867 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1868 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1869 _("FIXME: unable to rename"));
1871 /* Notify about operation end */
1872 modest_mail_operation_notify_end (self);
1873 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1874 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1875 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1876 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1877 _("FIXME: unable to rename"));
1878 /* Notify about operation end */
1879 modest_mail_operation_notify_end (self);
1881 TnyFolderStore *into;
1883 into = tny_folder_get_folder_store (folder);
1885 /* Check that the new folder name is not used by any
1886 special local folder */
1887 if (new_name_valid_if_local_account (priv, into, name)) {
1888 /* Create the helper */
1889 helper = g_slice_new0 (XFerMsgAsyncHelper);
1890 helper->mail_op = g_object_ref(self);
1891 helper->dest_folder = NULL;
1892 helper->headers = NULL;
1893 helper->user_callback = NULL;
1894 helper->user_data = NULL;
1896 /* Rename. Camel handles folder subscription/unsubscription */
1897 tny_folder_copy_async (folder, into, name, TRUE,
1899 transfer_folder_status_cb,
1902 modest_mail_operation_notify_end (self);
1904 g_object_unref (into);
1908 /* ******************************************************************* */
1909 /* ************************** MSG ACTIONS ************************* */
1910 /* ******************************************************************* */
1912 void modest_mail_operation_get_msg (ModestMailOperation *self,
1914 GetMsgAsyncUserCallback user_callback,
1917 GetMsgAsyncHelper *helper = NULL;
1919 ModestMailOperationPrivate *priv;
1921 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1922 g_return_if_fail (TNY_IS_HEADER (header));
1924 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1925 folder = tny_header_get_folder (header);
1927 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1929 /* Get message from folder */
1931 /* Get account and set it into mail_operation */
1932 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1934 helper = g_slice_new0 (GetMsgAsyncHelper);
1935 helper->mail_op = self;
1936 helper->user_callback = user_callback;
1937 helper->user_data = user_data;
1938 helper->header = g_object_ref (header);
1940 // The callback's reference so that the mail op is not
1941 // finalized until the async operation is completed even if
1942 // the user canceled the request meanwhile.
1943 g_object_ref (G_OBJECT (helper->mail_op));
1945 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1947 g_object_unref (G_OBJECT (folder));
1949 /* Set status failed and set an error */
1950 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1951 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1952 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1953 _("Error trying to get a message. No folder found for header"));
1955 /* Notify the queue */
1956 modest_mail_operation_notify_end (self);
1961 idle_get_mime_part_size_cb (gpointer userdata)
1963 GetMimePartSizeInfo *idle_info;
1965 idle_info = (GetMimePartSizeInfo *) userdata;
1967 gdk_threads_enter ();
1968 idle_info->callback (idle_info->mail_op,
1970 idle_info->userdata);
1971 gdk_threads_leave ();
1973 g_object_unref (idle_info->mail_op);
1974 g_slice_free (GetMimePartSizeInfo, idle_info);
1980 get_mime_part_size_thread (gpointer thr_user_data)
1982 GetMimePartSizeInfo *info;
1983 gchar read_buffer[GET_SIZE_BUFFER_SIZE];
1987 ModestMailOperationPrivate *priv;
1989 info = (GetMimePartSizeInfo *) thr_user_data;
1990 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1992 stream = tny_camel_mem_stream_new ();
1993 tny_mime_part_decode_to_stream (info->mime_part, stream);
1994 tny_stream_reset (stream);
1995 if (tny_stream_is_eos (stream)) {
1996 tny_stream_close (stream);
1997 stream = tny_mime_part_get_stream (info->mime_part);
2000 while (!tny_stream_is_eos (stream)) {
2001 readed_size = tny_stream_read (stream, read_buffer, GET_SIZE_BUFFER_SIZE);
2002 total += readed_size;
2005 if (info->callback) {
2006 GetMimePartSizeInfo *idle_info;
2008 idle_info = g_slice_new0 (GetMimePartSizeInfo);
2009 idle_info->mail_op = g_object_ref (info->mail_op);
2010 idle_info->size = total;
2011 idle_info->callback = info->callback;
2012 idle_info->userdata = info->userdata;
2013 g_idle_add (idle_get_mime_part_size_cb, idle_info);
2016 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2018 g_object_unref (info->mail_op);
2019 g_object_unref (stream);
2020 g_object_unref (info->mime_part);
2021 g_slice_free (GetMimePartSizeInfo, info);
2027 modest_mail_operation_get_mime_part_size (ModestMailOperation *self,
2029 GetMimePartSizeCallback user_callback,
2031 GDestroyNotify notify)
2033 GetMimePartSizeInfo *info;
2034 ModestMailOperationPrivate *priv;
2037 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2038 g_return_if_fail (TNY_IS_MIME_PART (part));
2040 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2042 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2043 info = g_slice_new0 (GetMimePartSizeInfo);
2044 info->mail_op = g_object_ref (self);
2045 info->mime_part = g_object_ref (part);
2046 info->callback = user_callback;
2047 info->userdata = user_data;
2049 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2054 get_msg_cb (TnyFolder *folder,
2060 GetMsgAsyncHelper *helper = NULL;
2061 ModestMailOperation *self = NULL;
2062 ModestMailOperationPrivate *priv = NULL;
2064 helper = (GetMsgAsyncHelper *) user_data;
2065 g_return_if_fail (helper != NULL);
2066 self = helper->mail_op;
2067 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2068 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2070 /* Check errors and cancel */
2072 priv->error = g_error_copy (*error);
2073 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2074 } else if (cancelled) {
2075 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2076 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2077 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2078 _("Error trying to refresh the contents of %s"),
2079 tny_folder_get_name (folder));
2081 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2084 /* If user defined callback function was defined, call it even
2085 if the operation failed*/
2086 if (helper->user_callback) {
2087 /* This callback is called into an iddle by tinymail,
2088 and idles are not in the main lock */
2089 gdk_threads_enter ();
2090 helper->user_callback (self, helper->header, msg, helper->user_data);
2091 gdk_threads_leave ();
2094 /* Notify about operation end */
2095 modest_mail_operation_notify_end (self);
2097 g_object_unref (helper->mail_op);
2098 g_object_unref (helper->header);
2099 g_slice_free (GetMsgAsyncHelper, helper);
2104 get_msg_status_cb (GObject *obj,
2108 GetMsgAsyncHelper *helper = NULL;
2109 ModestMailOperation *self;
2110 ModestMailOperationPrivate *priv;
2111 ModestMailOperationState *state;
2113 g_return_if_fail (status != NULL);
2114 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2116 helper = (GetMsgAsyncHelper *) user_data;
2117 g_return_if_fail (helper != NULL);
2119 self = helper->mail_op;
2120 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2125 state = modest_mail_operation_clone_state (self);
2126 state->bytes_done = status->position;
2127 state->bytes_total = status->of_total;
2128 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2129 gdk_threads_enter ();
2131 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2132 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2133 gdk_threads_leave ();
2135 g_slice_free (ModestMailOperationState, state);
2138 /****************************************************/
2140 ModestMailOperation *mail_op;
2142 GetMsgAsyncUserCallback user_callback;
2144 GDestroyNotify notify;
2148 GetMsgAsyncUserCallback user_callback;
2152 ModestMailOperation *mail_op;
2153 } NotifyGetMsgsInfo;
2157 * Used by get_msgs_full_thread to call the user_callback for each
2158 * message that has been read
2161 notify_get_msgs_full (gpointer data)
2163 NotifyGetMsgsInfo *info;
2165 info = (NotifyGetMsgsInfo *) data;
2167 /* Call the user callback. Idles are not in the main lock, so
2169 gdk_threads_enter ();
2170 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2171 gdk_threads_leave ();
2173 g_slice_free (NotifyGetMsgsInfo, info);
2179 * Used by get_msgs_full_thread to free al the thread resources and to
2180 * call the destroy function for the passed user_data
2183 get_msgs_full_destroyer (gpointer data)
2185 GetFullMsgsInfo *info;
2187 info = (GetFullMsgsInfo *) data;
2190 gdk_threads_enter ();
2191 info->notify (info->user_data);
2192 gdk_threads_leave ();
2196 g_object_unref (info->headers);
2197 g_slice_free (GetFullMsgsInfo, info);
2203 get_msgs_full_thread (gpointer thr_user_data)
2205 GetFullMsgsInfo *info;
2206 ModestMailOperationPrivate *priv = NULL;
2207 TnyIterator *iter = NULL;
2209 info = (GetFullMsgsInfo *) thr_user_data;
2210 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2212 iter = tny_list_create_iterator (info->headers);
2213 while (!tny_iterator_is_done (iter)) {
2217 header = TNY_HEADER (tny_iterator_get_current (iter));
2218 folder = tny_header_get_folder (header);
2220 /* Get message from folder */
2223 /* The callback will call it per each header */
2224 msg = tny_folder_get_msg (folder, header, &(priv->error));
2227 ModestMailOperationState *state;
2232 /* notify progress */
2233 state = modest_mail_operation_clone_state (info->mail_op);
2234 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2235 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2236 pair, (GDestroyNotify) modest_pair_free);
2238 /* The callback is the responsible for
2239 freeing the message */
2240 if (info->user_callback) {
2241 NotifyGetMsgsInfo *info_notify;
2242 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2243 info_notify->user_callback = info->user_callback;
2244 info_notify->mail_op = info->mail_op;
2245 info_notify->header = g_object_ref (header);
2246 info_notify->msg = g_object_ref (msg);
2247 info_notify->user_data = info->user_data;
2248 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2249 notify_get_msgs_full,
2252 g_object_unref (msg);
2255 /* Set status failed and set an error */
2256 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2257 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2258 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2259 "Error trying to get a message. No folder found for header");
2263 g_object_unref (header);
2265 tny_iterator_next (iter);
2268 /* Set operation status */
2269 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2270 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2272 /* Notify about operation end */
2273 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2275 /* Free thread resources. Will be called after all previous idles */
2276 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2282 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2283 TnyList *header_list,
2284 GetMsgAsyncUserCallback user_callback,
2286 GDestroyNotify notify)
2288 TnyHeader *header = NULL;
2289 TnyFolder *folder = NULL;
2291 ModestMailOperationPrivate *priv = NULL;
2292 GetFullMsgsInfo *info = NULL;
2293 gboolean size_ok = TRUE;
2295 TnyIterator *iter = NULL;
2297 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2299 /* Init mail operation */
2300 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2301 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2303 priv->total = tny_list_get_length(header_list);
2305 /* Get account and set it into mail_operation */
2306 if (tny_list_get_length (header_list) >= 1) {
2307 iter = tny_list_create_iterator (header_list);
2308 header = TNY_HEADER (tny_iterator_get_current (iter));
2310 folder = tny_header_get_folder (header);
2312 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2314 g_object_unref (folder);
2317 g_object_unref (header);
2320 if (tny_list_get_length (header_list) == 1) {
2321 g_object_unref (iter);
2326 /* Get msg size limit */
2327 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2328 MODEST_CONF_MSG_SIZE_LIMIT,
2331 g_clear_error (&(priv->error));
2332 max_size = G_MAXINT;
2334 max_size = max_size * KB;
2337 /* Check message size limits. If there is only one message
2338 always retrieve it */
2340 while (!tny_iterator_is_done (iter) && size_ok) {
2341 header = TNY_HEADER (tny_iterator_get_current (iter));
2343 if (tny_header_get_message_size (header) >= max_size)
2345 g_object_unref (header);
2348 tny_iterator_next (iter);
2350 g_object_unref (iter);
2354 /* Create the info */
2355 info = g_slice_new0 (GetFullMsgsInfo);
2356 info->mail_op = self;
2357 info->user_callback = user_callback;
2358 info->user_data = user_data;
2359 info->headers = g_object_ref (header_list);
2360 info->notify = notify;
2362 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2364 /* Set status failed and set an error */
2365 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2366 /* FIXME: the error msg is different for pop */
2367 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2368 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2369 _("emev_ni_ui_imap_msg_size_exceed_error"));
2370 /* Remove from queue and free resources */
2371 modest_mail_operation_notify_end (self);
2379 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2380 gboolean remove_to_trash /*ignored*/)
2383 ModestMailOperationPrivate *priv;
2385 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2386 g_return_if_fail (TNY_IS_HEADER (header));
2388 if (remove_to_trash)
2389 g_warning ("remove to trash is not implemented");
2391 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2392 folder = tny_header_get_folder (header);
2394 /* Get account and set it into mail_operation */
2395 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2397 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2400 tny_folder_remove_msg (folder, header, &(priv->error));
2402 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2403 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2405 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2406 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2407 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2408 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2411 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2417 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2419 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2422 g_object_unref (G_OBJECT (folder));
2424 /* Notify about operation end */
2425 modest_mail_operation_notify_end (self);
2429 transfer_msgs_status_cb (GObject *obj,
2433 XFerMsgAsyncHelper *helper = NULL;
2434 ModestMailOperation *self;
2435 ModestMailOperationPrivate *priv;
2436 ModestMailOperationState *state;
2439 g_return_if_fail (status != NULL);
2440 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2442 helper = (XFerMsgAsyncHelper *) user_data;
2443 g_return_if_fail (helper != NULL);
2445 self = helper->mail_op;
2446 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2448 priv->done = status->position;
2449 priv->total = status->of_total;
2451 state = modest_mail_operation_clone_state (self);
2452 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2453 gdk_threads_enter ();
2455 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2456 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2457 gdk_threads_leave ();
2459 g_slice_free (ModestMailOperationState, state);
2464 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2466 XFerMsgAsyncHelper *helper;
2467 ModestMailOperation *self;
2468 ModestMailOperationPrivate *priv;
2470 helper = (XFerMsgAsyncHelper *) user_data;
2471 self = helper->mail_op;
2473 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2476 priv->error = g_error_copy (*err);
2478 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2479 } else if (cancelled) {
2480 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2481 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2482 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2483 _("Error trying to refresh the contents of %s"),
2484 tny_folder_get_name (folder));
2487 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2490 /* Notify about operation end */
2491 modest_mail_operation_notify_end (self);
2493 /* If user defined callback function was defined, call it */
2494 if (helper->user_callback) {
2495 gdk_threads_enter ();
2496 helper->user_callback (priv->source, helper->user_data);
2497 gdk_threads_leave ();
2501 g_object_unref (helper->headers);
2502 g_object_unref (helper->dest_folder);
2503 g_object_unref (helper->mail_op);
2504 g_slice_free (XFerMsgAsyncHelper, helper);
2505 g_object_unref (folder);
2510 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2513 gboolean delete_original,
2514 XferMsgsAsynUserCallback user_callback,
2517 ModestMailOperationPrivate *priv = NULL;
2518 TnyIterator *iter = NULL;
2519 TnyFolder *src_folder = NULL;
2520 XFerMsgAsyncHelper *helper = NULL;
2521 TnyHeader *header = NULL;
2522 ModestTnyFolderRules rules = 0;
2523 const gchar *id1 = NULL;
2524 const gchar *id2 = NULL;
2525 gboolean same_folder = FALSE;
2527 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2528 g_return_if_fail (TNY_IS_LIST (headers));
2529 g_return_if_fail (TNY_IS_FOLDER (folder));
2531 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2534 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2536 /* Apply folder rules */
2537 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2538 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2539 /* Set status failed and set an error */
2540 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2541 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2542 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2543 _CS("ckct_ib_unable_to_paste_here"));
2544 /* Notify the queue */
2545 modest_mail_operation_notify_end (self);
2549 /* Get source folder */
2550 iter = tny_list_create_iterator (headers);
2551 header = TNY_HEADER (tny_iterator_get_current (iter));
2553 src_folder = tny_header_get_folder (header);
2554 g_object_unref (header);
2557 g_object_unref (iter);
2559 /* Check folder source and destination */
2560 id1 = tny_folder_get_id (src_folder);
2561 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2562 same_folder = !g_ascii_strcasecmp (id1, id2);
2564 /* Set status failed and set an error */
2565 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2566 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2567 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2568 _("mcen_ib_unable_to_copy_samefolder"));
2570 /* Notify the queue */
2571 modest_mail_operation_notify_end (self);
2574 g_object_unref (src_folder);
2578 /* Create the helper */
2579 helper = g_slice_new0 (XFerMsgAsyncHelper);
2580 helper->mail_op = g_object_ref(self);
2581 helper->dest_folder = g_object_ref(folder);
2582 helper->headers = g_object_ref(headers);
2583 helper->user_callback = user_callback;
2584 helper->user_data = user_data;
2586 /* Get account and set it into mail_operation */
2587 priv->account = modest_tny_folder_get_account (src_folder);
2589 /* Transfer messages */
2590 tny_folder_transfer_msgs_async (src_folder,
2595 transfer_msgs_status_cb,
2601 on_refresh_folder (TnyFolder *folder,
2606 RefreshAsyncHelper *helper = NULL;
2607 ModestMailOperation *self = NULL;
2608 ModestMailOperationPrivate *priv = NULL;
2610 helper = (RefreshAsyncHelper *) user_data;
2611 self = helper->mail_op;
2612 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2615 priv->error = g_error_copy (*error);
2616 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2621 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2622 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2623 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2624 _("Error trying to refresh the contents of %s"),
2625 tny_folder_get_name (folder));
2629 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2631 /* Call user defined callback, if it exists */
2632 if (helper->user_callback) {
2633 gdk_threads_enter ();
2634 helper->user_callback (self, folder, helper->user_data);
2635 gdk_threads_leave ();
2639 g_slice_free (RefreshAsyncHelper, helper);
2641 /* Notify about operation end */
2642 modest_mail_operation_notify_end (self);
2646 on_refresh_folder_status_update (GObject *obj,
2650 RefreshAsyncHelper *helper = NULL;
2651 ModestMailOperation *self = NULL;
2652 ModestMailOperationPrivate *priv = NULL;
2653 ModestMailOperationState *state;
2655 g_return_if_fail (user_data != NULL);
2656 g_return_if_fail (status != NULL);
2657 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2659 helper = (RefreshAsyncHelper *) user_data;
2660 self = helper->mail_op;
2661 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2663 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2665 priv->done = status->position;
2666 priv->total = status->of_total;
2668 state = modest_mail_operation_clone_state (self);
2669 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2670 gdk_threads_enter ();
2672 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2673 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2674 gdk_threads_leave ();
2676 g_slice_free (ModestMailOperationState, state);
2680 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2682 RefreshAsyncUserCallback user_callback,
2685 ModestMailOperationPrivate *priv = NULL;
2686 RefreshAsyncHelper *helper = NULL;
2688 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2690 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2692 /* Get account and set it into mail_operation */
2693 priv->account = modest_tny_folder_get_account (folder);
2695 /* Create the helper */
2696 helper = g_slice_new0 (RefreshAsyncHelper);
2697 helper->mail_op = self;
2698 helper->user_callback = user_callback;
2699 helper->user_data = user_data;
2701 /* Refresh the folder. TODO: tinymail could issue a status
2702 updates before the callback call then this could happen. We
2703 must review the design */
2704 tny_folder_refresh_async (folder,
2706 on_refresh_folder_status_update,
2712 * It's used by the mail operation queue to notify the observers
2713 * attached to that signal that the operation finished. We need to use
2714 * that because tinymail does not give us the progress of a given
2715 * operation when it finishes (it directly calls the operation
2719 modest_mail_operation_notify_end (ModestMailOperation *self)
2721 ModestMailOperationState *state;
2722 ModestMailOperationPrivate *priv = NULL;
2724 g_return_if_fail (self);
2726 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2728 /* Set the account back to not busy */
2729 if (priv->account_name) {
2730 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2731 priv->account_name, FALSE);
2732 g_free(priv->account_name);
2733 priv->account_name = NULL;
2736 /* Notify the observers about the mail operation end */
2737 /* We do not wrapp this emission because we assume that this
2738 function is always called from within the main lock */
2739 state = modest_mail_operation_clone_state (self);
2740 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2741 g_slice_free (ModestMailOperationState, state);