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");
828 tny_folder_add_msg (folder, msg, &(priv->error));
830 if ((!priv->error) && (info->draft_msg != NULL)) {
831 header = tny_msg_get_header (info->draft_msg);
832 src_folder = tny_header_get_folder (header);
833 /* Remove the old draft expunging it */
834 tny_folder_remove_msg (src_folder, header, NULL);
835 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
836 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
837 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */
838 g_object_unref (header);
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 tny_camel_mem_stream_get_type ();
2051 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2056 get_msg_cb (TnyFolder *folder,
2062 GetMsgAsyncHelper *helper = NULL;
2063 ModestMailOperation *self = NULL;
2064 ModestMailOperationPrivate *priv = NULL;
2066 helper = (GetMsgAsyncHelper *) user_data;
2067 g_return_if_fail (helper != NULL);
2068 self = helper->mail_op;
2069 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2070 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2072 /* Check errors and cancel */
2074 priv->error = g_error_copy (*error);
2075 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2076 } else if (cancelled) {
2077 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2078 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2079 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2080 _("Error trying to refresh the contents of %s"),
2081 tny_folder_get_name (folder));
2083 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2086 /* If user defined callback function was defined, call it even
2087 if the operation failed*/
2088 if (helper->user_callback) {
2089 /* This callback is called into an iddle by tinymail,
2090 and idles are not in the main lock */
2091 gdk_threads_enter ();
2092 helper->user_callback (self, helper->header, msg, helper->user_data);
2093 gdk_threads_leave ();
2096 /* Notify about operation end */
2097 modest_mail_operation_notify_end (self);
2099 g_object_unref (helper->mail_op);
2100 g_object_unref (helper->header);
2101 g_slice_free (GetMsgAsyncHelper, helper);
2106 get_msg_status_cb (GObject *obj,
2110 GetMsgAsyncHelper *helper = NULL;
2111 ModestMailOperation *self;
2112 ModestMailOperationPrivate *priv;
2113 ModestMailOperationState *state;
2115 g_return_if_fail (status != NULL);
2116 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2118 helper = (GetMsgAsyncHelper *) user_data;
2119 g_return_if_fail (helper != NULL);
2121 self = helper->mail_op;
2122 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2127 state = modest_mail_operation_clone_state (self);
2128 state->bytes_done = status->position;
2129 state->bytes_total = status->of_total;
2130 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2131 gdk_threads_enter ();
2133 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2134 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2135 gdk_threads_leave ();
2137 g_slice_free (ModestMailOperationState, state);
2140 /****************************************************/
2142 ModestMailOperation *mail_op;
2144 GetMsgAsyncUserCallback user_callback;
2146 GDestroyNotify notify;
2150 GetMsgAsyncUserCallback user_callback;
2154 ModestMailOperation *mail_op;
2155 } NotifyGetMsgsInfo;
2159 * Used by get_msgs_full_thread to call the user_callback for each
2160 * message that has been read
2163 notify_get_msgs_full (gpointer data)
2165 NotifyGetMsgsInfo *info;
2167 info = (NotifyGetMsgsInfo *) data;
2169 /* Call the user callback. Idles are not in the main lock, so
2171 gdk_threads_enter ();
2172 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2173 gdk_threads_leave ();
2175 g_slice_free (NotifyGetMsgsInfo, info);
2181 * Used by get_msgs_full_thread to free al the thread resources and to
2182 * call the destroy function for the passed user_data
2185 get_msgs_full_destroyer (gpointer data)
2187 GetFullMsgsInfo *info;
2189 info = (GetFullMsgsInfo *) data;
2192 gdk_threads_enter ();
2193 info->notify (info->user_data);
2194 gdk_threads_leave ();
2198 g_object_unref (info->headers);
2199 g_slice_free (GetFullMsgsInfo, info);
2205 get_msgs_full_thread (gpointer thr_user_data)
2207 GetFullMsgsInfo *info;
2208 ModestMailOperationPrivate *priv = NULL;
2209 TnyIterator *iter = NULL;
2211 info = (GetFullMsgsInfo *) thr_user_data;
2212 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2214 iter = tny_list_create_iterator (info->headers);
2215 while (!tny_iterator_is_done (iter)) {
2219 header = TNY_HEADER (tny_iterator_get_current (iter));
2220 folder = tny_header_get_folder (header);
2222 /* Get message from folder */
2225 /* The callback will call it per each header */
2226 msg = tny_folder_get_msg (folder, header, &(priv->error));
2229 ModestMailOperationState *state;
2234 /* notify progress */
2235 state = modest_mail_operation_clone_state (info->mail_op);
2236 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2237 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2238 pair, (GDestroyNotify) modest_pair_free);
2240 /* The callback is the responsible for
2241 freeing the message */
2242 if (info->user_callback) {
2243 NotifyGetMsgsInfo *info_notify;
2244 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2245 info_notify->user_callback = info->user_callback;
2246 info_notify->mail_op = info->mail_op;
2247 info_notify->header = g_object_ref (header);
2248 info_notify->msg = g_object_ref (msg);
2249 info_notify->user_data = info->user_data;
2250 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2251 notify_get_msgs_full,
2254 g_object_unref (msg);
2257 /* Set status failed and set an error */
2258 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2259 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2260 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2261 "Error trying to get a message. No folder found for header");
2265 g_object_unref (header);
2267 tny_iterator_next (iter);
2270 /* Set operation status */
2271 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2272 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2274 /* Notify about operation end */
2275 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2277 /* Free thread resources. Will be called after all previous idles */
2278 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2284 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2285 TnyList *header_list,
2286 GetMsgAsyncUserCallback user_callback,
2288 GDestroyNotify notify)
2290 TnyHeader *header = NULL;
2291 TnyFolder *folder = NULL;
2293 ModestMailOperationPrivate *priv = NULL;
2294 GetFullMsgsInfo *info = NULL;
2295 gboolean size_ok = TRUE;
2297 TnyIterator *iter = NULL;
2299 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2301 /* Init mail operation */
2302 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2303 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2305 priv->total = tny_list_get_length(header_list);
2307 /* Get account and set it into mail_operation */
2308 if (tny_list_get_length (header_list) >= 1) {
2309 iter = tny_list_create_iterator (header_list);
2310 header = TNY_HEADER (tny_iterator_get_current (iter));
2312 folder = tny_header_get_folder (header);
2314 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2316 g_object_unref (folder);
2319 g_object_unref (header);
2322 if (tny_list_get_length (header_list) == 1) {
2323 g_object_unref (iter);
2328 /* Get msg size limit */
2329 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2330 MODEST_CONF_MSG_SIZE_LIMIT,
2333 g_clear_error (&(priv->error));
2334 max_size = G_MAXINT;
2336 max_size = max_size * KB;
2339 /* Check message size limits. If there is only one message
2340 always retrieve it */
2342 while (!tny_iterator_is_done (iter) && size_ok) {
2343 header = TNY_HEADER (tny_iterator_get_current (iter));
2345 if (tny_header_get_message_size (header) >= max_size)
2347 g_object_unref (header);
2350 tny_iterator_next (iter);
2352 g_object_unref (iter);
2356 /* Create the info */
2357 info = g_slice_new0 (GetFullMsgsInfo);
2358 info->mail_op = self;
2359 info->user_callback = user_callback;
2360 info->user_data = user_data;
2361 info->headers = g_object_ref (header_list);
2362 info->notify = notify;
2364 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2366 /* Set status failed and set an error */
2367 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2368 /* FIXME: the error msg is different for pop */
2369 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2370 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2371 _("emev_ni_ui_imap_msg_size_exceed_error"));
2372 /* Remove from queue and free resources */
2373 modest_mail_operation_notify_end (self);
2381 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2382 gboolean remove_to_trash /*ignored*/)
2385 ModestMailOperationPrivate *priv;
2387 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2388 g_return_if_fail (TNY_IS_HEADER (header));
2390 if (remove_to_trash)
2391 g_warning ("remove to trash is not implemented");
2393 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2394 folder = tny_header_get_folder (header);
2396 /* Get account and set it into mail_operation */
2397 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2399 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2402 tny_folder_remove_msg (folder, header, &(priv->error));
2404 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2405 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2407 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2408 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2409 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2410 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2413 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2419 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2421 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2424 g_object_unref (G_OBJECT (folder));
2426 /* Notify about operation end */
2427 modest_mail_operation_notify_end (self);
2431 transfer_msgs_status_cb (GObject *obj,
2435 XFerMsgAsyncHelper *helper = NULL;
2436 ModestMailOperation *self;
2437 ModestMailOperationPrivate *priv;
2438 ModestMailOperationState *state;
2441 g_return_if_fail (status != NULL);
2442 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2444 helper = (XFerMsgAsyncHelper *) user_data;
2445 g_return_if_fail (helper != NULL);
2447 self = helper->mail_op;
2448 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2450 priv->done = status->position;
2451 priv->total = status->of_total;
2453 state = modest_mail_operation_clone_state (self);
2454 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2455 gdk_threads_enter ();
2457 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2458 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2459 gdk_threads_leave ();
2461 g_slice_free (ModestMailOperationState, state);
2466 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2468 XFerMsgAsyncHelper *helper;
2469 ModestMailOperation *self;
2470 ModestMailOperationPrivate *priv;
2472 helper = (XFerMsgAsyncHelper *) user_data;
2473 self = helper->mail_op;
2475 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2478 priv->error = g_error_copy (*err);
2480 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2481 } else if (cancelled) {
2482 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2483 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2484 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2485 _("Error trying to refresh the contents of %s"),
2486 tny_folder_get_name (folder));
2489 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2492 /* Notify about operation end */
2493 modest_mail_operation_notify_end (self);
2495 /* If user defined callback function was defined, call it */
2496 if (helper->user_callback) {
2497 gdk_threads_enter ();
2498 helper->user_callback (priv->source, helper->user_data);
2499 gdk_threads_leave ();
2503 g_object_unref (helper->headers);
2504 g_object_unref (helper->dest_folder);
2505 g_object_unref (helper->mail_op);
2506 g_slice_free (XFerMsgAsyncHelper, helper);
2507 g_object_unref (folder);
2512 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2515 gboolean delete_original,
2516 XferMsgsAsynUserCallback user_callback,
2519 ModestMailOperationPrivate *priv = NULL;
2520 TnyIterator *iter = NULL;
2521 TnyFolder *src_folder = NULL;
2522 XFerMsgAsyncHelper *helper = NULL;
2523 TnyHeader *header = NULL;
2524 ModestTnyFolderRules rules = 0;
2525 const gchar *id1 = NULL;
2526 const gchar *id2 = NULL;
2527 gboolean same_folder = FALSE;
2529 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2530 g_return_if_fail (TNY_IS_LIST (headers));
2531 g_return_if_fail (TNY_IS_FOLDER (folder));
2533 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2536 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2538 /* Apply folder rules */
2539 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2540 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2541 /* Set status failed and set an error */
2542 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2543 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2544 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2545 _CS("ckct_ib_unable_to_paste_here"));
2546 /* Notify the queue */
2547 modest_mail_operation_notify_end (self);
2551 /* Get source folder */
2552 iter = tny_list_create_iterator (headers);
2553 header = TNY_HEADER (tny_iterator_get_current (iter));
2555 src_folder = tny_header_get_folder (header);
2556 g_object_unref (header);
2559 g_object_unref (iter);
2561 /* Check folder source and destination */
2562 id1 = tny_folder_get_id (src_folder);
2563 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2564 same_folder = !g_ascii_strcasecmp (id1, id2);
2566 /* Set status failed and set an error */
2567 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2568 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2569 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2570 _("mcen_ib_unable_to_copy_samefolder"));
2572 /* Notify the queue */
2573 modest_mail_operation_notify_end (self);
2576 g_object_unref (src_folder);
2580 /* Create the helper */
2581 helper = g_slice_new0 (XFerMsgAsyncHelper);
2582 helper->mail_op = g_object_ref(self);
2583 helper->dest_folder = g_object_ref(folder);
2584 helper->headers = g_object_ref(headers);
2585 helper->user_callback = user_callback;
2586 helper->user_data = user_data;
2588 /* Get account and set it into mail_operation */
2589 priv->account = modest_tny_folder_get_account (src_folder);
2591 /* Transfer messages */
2592 tny_folder_transfer_msgs_async (src_folder,
2597 transfer_msgs_status_cb,
2603 on_refresh_folder (TnyFolder *folder,
2608 RefreshAsyncHelper *helper = NULL;
2609 ModestMailOperation *self = NULL;
2610 ModestMailOperationPrivate *priv = NULL;
2612 helper = (RefreshAsyncHelper *) user_data;
2613 self = helper->mail_op;
2614 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2617 priv->error = g_error_copy (*error);
2618 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2623 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2624 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2625 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2626 _("Error trying to refresh the contents of %s"),
2627 tny_folder_get_name (folder));
2631 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2633 /* Call user defined callback, if it exists */
2634 if (helper->user_callback) {
2635 gdk_threads_enter ();
2636 helper->user_callback (self, folder, helper->user_data);
2637 gdk_threads_leave ();
2641 g_slice_free (RefreshAsyncHelper, helper);
2643 /* Notify about operation end */
2644 modest_mail_operation_notify_end (self);
2648 on_refresh_folder_status_update (GObject *obj,
2652 RefreshAsyncHelper *helper = NULL;
2653 ModestMailOperation *self = NULL;
2654 ModestMailOperationPrivate *priv = NULL;
2655 ModestMailOperationState *state;
2657 g_return_if_fail (user_data != NULL);
2658 g_return_if_fail (status != NULL);
2659 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2661 helper = (RefreshAsyncHelper *) user_data;
2662 self = helper->mail_op;
2663 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2665 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2667 priv->done = status->position;
2668 priv->total = status->of_total;
2670 state = modest_mail_operation_clone_state (self);
2671 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2672 gdk_threads_enter ();
2674 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2675 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2676 gdk_threads_leave ();
2678 g_slice_free (ModestMailOperationState, state);
2682 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2684 RefreshAsyncUserCallback user_callback,
2687 ModestMailOperationPrivate *priv = NULL;
2688 RefreshAsyncHelper *helper = NULL;
2690 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2692 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2694 /* Get account and set it into mail_operation */
2695 priv->account = modest_tny_folder_get_account (folder);
2697 /* Create the helper */
2698 helper = g_slice_new0 (RefreshAsyncHelper);
2699 helper->mail_op = self;
2700 helper->user_callback = user_callback;
2701 helper->user_data = user_data;
2703 /* Refresh the folder. TODO: tinymail could issue a status
2704 updates before the callback call then this could happen. We
2705 must review the design */
2706 tny_folder_refresh_async (folder,
2708 on_refresh_folder_status_update,
2714 * It's used by the mail operation queue to notify the observers
2715 * attached to that signal that the operation finished. We need to use
2716 * that because tinymail does not give us the progress of a given
2717 * operation when it finishes (it directly calls the operation
2721 modest_mail_operation_notify_end (ModestMailOperation *self)
2723 ModestMailOperationState *state;
2724 ModestMailOperationPrivate *priv = NULL;
2726 g_return_if_fail (self);
2728 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2730 /* Set the account back to not busy */
2731 if (priv->account_name) {
2732 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2733 priv->account_name, FALSE);
2734 g_free(priv->account_name);
2735 priv->account_name = NULL;
2738 /* Notify the observers about the mail operation end */
2739 /* We do not wrapp this emission because we assume that this
2740 function is always called from within the main lock */
2741 state = modest_mail_operation_clone_state (self);
2742 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2743 g_slice_free (ModestMailOperationState, state);