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-account-mgr-helpers.h"
49 #include <modest-tny-account.h>
50 #include <modest-tny-send-queue.h>
51 #include <modest-runtime.h>
52 #include "modest-text-utils.h"
53 #include "modest-tny-msg.h"
54 #include "modest-tny-folder.h"
55 #include "modest-tny-account-store.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-marshal.h"
58 #include "modest-error.h"
59 #include "modest-mail-operation.h"
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_start (ModestMailOperation *self);
85 static void modest_mail_operation_notify_end (ModestMailOperation *self);
87 enum _ModestMailOperationSignals
89 PROGRESS_CHANGED_SIGNAL,
90 OPERATION_STARTED_SIGNAL,
91 OPERATION_FINISHED_SIGNAL,
95 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
96 struct _ModestMailOperationPrivate {
102 ErrorCheckingUserCallback error_checking;
103 gpointer error_checking_user_data;
104 ModestMailOperationStatus status;
105 ModestMailOperationTypeOperation op_type;
108 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
109 MODEST_TYPE_MAIL_OPERATION, \
110 ModestMailOperationPrivate))
112 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
113 priv->status = new_status;\
116 typedef struct _GetMsgAsyncHelper {
117 ModestMailOperation *mail_op;
119 GetMsgAsyncUserCallback user_callback;
123 typedef struct _RefreshAsyncHelper {
124 ModestMailOperation *mail_op;
125 RefreshAsyncUserCallback user_callback;
127 } RefreshAsyncHelper;
129 typedef struct _XFerMsgAsyncHelper
131 ModestMailOperation *mail_op;
133 TnyFolder *dest_folder;
134 XferAsyncUserCallback user_callback;
137 } XFerMsgAsyncHelper;
139 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
143 static void modest_mail_operation_create_msg (ModestMailOperation *self,
144 const gchar *from, const gchar *to,
145 const gchar *cc, const gchar *bcc,
146 const gchar *subject, const gchar *plain_body,
147 const gchar *html_body, const GList *attachments_list,
148 const GList *images_list,
149 TnyHeaderFlags priority_flags,
150 ModestMailOperationCreateMsgCallback callback,
153 static gboolean idle_notify_queue (gpointer data);
156 ModestMailOperation *mail_op;
164 GList *attachments_list;
166 TnyHeaderFlags priority_flags;
167 ModestMailOperationCreateMsgCallback callback;
173 ModestMailOperation *mail_op;
175 ModestMailOperationCreateMsgCallback callback;
180 static GObjectClass *parent_class = NULL;
182 static guint signals[NUM_SIGNALS] = {0};
185 modest_mail_operation_get_type (void)
187 static GType my_type = 0;
189 static const GTypeInfo my_info = {
190 sizeof(ModestMailOperationClass),
191 NULL, /* base init */
192 NULL, /* base finalize */
193 (GClassInitFunc) modest_mail_operation_class_init,
194 NULL, /* class finalize */
195 NULL, /* class data */
196 sizeof(ModestMailOperation),
198 (GInstanceInitFunc) modest_mail_operation_init,
201 my_type = g_type_register_static (G_TYPE_OBJECT,
202 "ModestMailOperation",
209 modest_mail_operation_class_init (ModestMailOperationClass *klass)
211 GObjectClass *gobject_class;
212 gobject_class = (GObjectClass*) klass;
214 parent_class = g_type_class_peek_parent (klass);
215 gobject_class->finalize = modest_mail_operation_finalize;
217 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
220 * ModestMailOperation::progress-changed
221 * @self: the #MailOperation that emits the signal
222 * @user_data: user data set when the signal handler was connected
224 * Emitted when the progress of a mail operation changes
226 signals[PROGRESS_CHANGED_SIGNAL] =
227 g_signal_new ("progress-changed",
228 G_TYPE_FROM_CLASS (gobject_class),
230 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
232 g_cclosure_marshal_VOID__POINTER,
233 G_TYPE_NONE, 1, G_TYPE_POINTER);
237 * This signal is issued whenever a mail operation starts, and
238 * starts mean when the tinymail operation is issued. This
239 * means that it could happen that something wrong happens and
240 * the tinymail function is never called. In this situation a
241 * operation-finished will be issued without any
244 signals[OPERATION_STARTED_SIGNAL] =
245 g_signal_new ("operation-started",
246 G_TYPE_FROM_CLASS (gobject_class),
248 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
250 g_cclosure_marshal_VOID__VOID,
255 * This signal is issued whenever a mail operation
256 * finishes. Note that this signal could be issued without any
257 * previous "operation-started" signal, because this last one
258 * is only issued when the tinymail operation is successfully
261 signals[OPERATION_FINISHED_SIGNAL] =
262 g_signal_new ("operation-finished",
263 G_TYPE_FROM_CLASS (gobject_class),
265 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
267 g_cclosure_marshal_VOID__VOID,
272 modest_mail_operation_init (ModestMailOperation *obj)
274 ModestMailOperationPrivate *priv;
276 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
278 priv->account = NULL;
279 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
280 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
285 priv->error_checking = NULL;
286 priv->error_checking_user_data = NULL;
290 modest_mail_operation_finalize (GObject *obj)
292 ModestMailOperationPrivate *priv;
294 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
299 g_error_free (priv->error);
303 g_object_unref (priv->source);
307 g_object_unref (priv->account);
308 priv->account = NULL;
312 G_OBJECT_CLASS(parent_class)->finalize (obj);
316 modest_mail_operation_new (GObject *source)
318 ModestMailOperation *obj;
319 ModestMailOperationPrivate *priv;
321 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
322 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
325 priv->source = g_object_ref(source);
331 modest_mail_operation_new_with_error_handling (GObject *source,
332 ErrorCheckingUserCallback error_handler,
335 ModestMailOperation *obj;
336 ModestMailOperationPrivate *priv;
338 obj = modest_mail_operation_new (source);
339 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
341 g_return_val_if_fail (error_handler != NULL, obj);
342 priv->error_checking = error_handler;
343 priv->error_checking_user_data = user_data;
349 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
351 ModestMailOperationPrivate *priv;
353 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
354 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
356 if (priv->error_checking != NULL)
357 priv->error_checking (self, priv->error_checking_user_data);
361 ModestMailOperationTypeOperation
362 modest_mail_operation_get_type_operation (ModestMailOperation *self)
364 ModestMailOperationPrivate *priv;
366 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
368 return priv->op_type;
372 modest_mail_operation_is_mine (ModestMailOperation *self,
375 ModestMailOperationPrivate *priv;
377 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
378 if (priv->source == NULL) return FALSE;
380 return priv->source == me;
384 modest_mail_operation_get_source (ModestMailOperation *self)
386 ModestMailOperationPrivate *priv;
388 g_return_val_if_fail (self, NULL);
390 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
392 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
396 return (priv->source) ? g_object_ref (priv->source) : NULL;
399 ModestMailOperationStatus
400 modest_mail_operation_get_status (ModestMailOperation *self)
402 ModestMailOperationPrivate *priv;
404 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
405 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
406 MODEST_MAIL_OPERATION_STATUS_INVALID);
408 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
410 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
411 return MODEST_MAIL_OPERATION_STATUS_INVALID;
418 modest_mail_operation_get_error (ModestMailOperation *self)
420 ModestMailOperationPrivate *priv;
422 g_return_val_if_fail (self, NULL);
423 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
425 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
428 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
436 modest_mail_operation_cancel (ModestMailOperation *self)
438 ModestMailOperationPrivate *priv;
439 gboolean canceled = FALSE;
441 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
443 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
445 /* Note that if we call cancel with an already canceled mail
446 operation the progress changed signal won't be emitted */
447 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
451 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
453 /* Cancel the mail operation. We need to wrap it between this
454 start/stop operations to allow following calls to the
456 g_return_val_if_fail (priv->account, FALSE);
457 tny_account_cancel (priv->account);
463 modest_mail_operation_get_task_done (ModestMailOperation *self)
465 ModestMailOperationPrivate *priv;
467 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
469 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
474 modest_mail_operation_get_task_total (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_is_finished (ModestMailOperation *self)
487 ModestMailOperationPrivate *priv;
488 gboolean retval = FALSE;
490 if (!MODEST_IS_MAIL_OPERATION (self)) {
491 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
495 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
497 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
498 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
499 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
500 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
510 * Creates an image of the current state of a mail operation, the
511 * caller must free it
513 static ModestMailOperationState *
514 modest_mail_operation_clone_state (ModestMailOperation *self)
516 ModestMailOperationState *state;
517 ModestMailOperationPrivate *priv;
519 /* FIXME: this should be fixed properly
521 * in some cases, priv was NULL, so checking here to
524 g_return_val_if_fail (self, NULL);
525 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
526 g_return_val_if_fail (priv, NULL);
531 state = g_slice_new (ModestMailOperationState);
533 state->status = priv->status;
534 state->op_type = priv->op_type;
535 state->done = priv->done;
536 state->total = priv->total;
537 state->finished = modest_mail_operation_is_finished (self);
538 state->bytes_done = 0;
539 state->bytes_total = 0;
544 /* ******************************************************************* */
545 /* ************************** SEND ACTIONS ************************* */
546 /* ******************************************************************* */
549 modest_mail_operation_send_mail (ModestMailOperation *self,
550 TnyTransportAccount *transport_account,
553 TnySendQueue *send_queue = NULL;
554 ModestMailOperationPrivate *priv;
556 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
557 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
558 g_return_if_fail (TNY_IS_MSG (msg));
560 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
562 /* Get account and set it into mail_operation */
563 priv->account = g_object_ref (transport_account);
567 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
568 if (!TNY_IS_SEND_QUEUE(send_queue)) {
569 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
570 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
571 "modest: could not find send queue for account\n");
572 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
575 /* Add the msg to the queue */
576 modest_mail_operation_notify_start (self);
577 modest_tny_send_queue_add (MODEST_TNY_SEND_QUEUE(send_queue),
581 /* TODO: we're setting always success, do the check in
583 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
586 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)
587 modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
589 /* TODO: do this in the handler of the "msg-sent"
590 signal.Notify about operation end */
591 modest_mail_operation_notify_end (self);
595 idle_create_msg_cb (gpointer idle_data)
597 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
599 /* This is a GDK lock because we are an idle callback and
600 * info->callback can contain Gtk+ code */
602 gdk_threads_enter (); /* CHECKED */
603 info->callback (info->mail_op, info->msg, info->userdata);
605 g_object_unref (info->mail_op);
607 g_object_unref (info->msg);
608 g_slice_free (CreateMsgIdleInfo, info);
609 gdk_threads_leave (); /* CHECKED */
615 create_msg_thread (gpointer thread_data)
617 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
618 TnyMsg *new_msg = NULL;
619 ModestMailOperationPrivate *priv;
621 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
622 if (info->html_body == NULL) {
623 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
624 info->bcc, info->subject, info->plain_body,
625 info->attachments_list);
627 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
628 info->bcc, info->subject, info->html_body,
629 info->plain_body, info->attachments_list,
635 TnyHeaderFlags flags = 0;
637 /* Set priority flags in message */
638 header = tny_msg_get_header (new_msg);
639 if (info->priority_flags != 0)
640 flags |= info->priority_flags;
642 /* Set attachment flags in message */
643 if (info->attachments_list != NULL)
644 flags |= TNY_HEADER_FLAG_ATTACHMENTS;
646 tny_header_set_flags (header, flags);
647 g_object_unref (G_OBJECT(header));
649 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
650 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
651 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
652 "modest: failed to create a new msg\n");
660 g_free (info->plain_body);
661 g_free (info->html_body);
662 g_free (info->subject);
663 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
664 g_list_free (info->attachments_list);
665 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
666 g_list_free (info->images_list);
668 if (info->callback) {
669 CreateMsgIdleInfo *idle_info;
670 idle_info = g_slice_new0 (CreateMsgIdleInfo);
671 idle_info->mail_op = info->mail_op;
672 g_object_ref (info->mail_op);
673 idle_info->msg = new_msg;
675 g_object_ref (new_msg);
676 idle_info->callback = info->callback;
677 idle_info->userdata = info->userdata;
678 g_idle_add (idle_create_msg_cb, idle_info);
680 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
683 g_object_unref (info->mail_op);
684 g_slice_free (CreateMsgInfo, info);
689 modest_mail_operation_create_msg (ModestMailOperation *self,
690 const gchar *from, const gchar *to,
691 const gchar *cc, const gchar *bcc,
692 const gchar *subject, const gchar *plain_body,
693 const gchar *html_body,
694 const GList *attachments_list,
695 const GList *images_list,
696 TnyHeaderFlags priority_flags,
697 ModestMailOperationCreateMsgCallback callback,
700 CreateMsgInfo *info = NULL;
702 info = g_slice_new0 (CreateMsgInfo);
703 info->mail_op = self;
706 info->from = g_strdup (from);
707 info->to = g_strdup (to);
708 info->cc = g_strdup (cc);
709 info->bcc = g_strdup (bcc);
710 info->subject = g_strdup (subject);
711 info->plain_body = g_strdup (plain_body);
712 info->html_body = g_strdup (html_body);
713 info->attachments_list = g_list_copy ((GList *) attachments_list);
714 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
715 info->images_list = g_list_copy ((GList *) images_list);
716 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
717 info->priority_flags = priority_flags;
719 info->callback = callback;
720 info->userdata = userdata;
722 g_thread_create (create_msg_thread, info, FALSE, NULL);
727 TnyTransportAccount *transport_account;
732 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
736 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
737 TnyFolder *draft_folder = NULL;
738 TnyFolder *outbox_folder = NULL;
746 /* Call mail operation */
747 modest_mail_operation_send_mail (self, info->transport_account, msg);
749 /* Remove old mail from its source folder */
750 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
751 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_OUTBOX);
752 if (info->draft_msg != NULL) {
753 TnyFolder *folder = NULL;
754 TnyFolder *src_folder = NULL;
755 TnyFolderType folder_type;
756 folder = tny_msg_get_folder (info->draft_msg);
757 if (folder == NULL) goto end;
758 folder_type = modest_tny_folder_guess_folder_type (folder);
759 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
760 src_folder = outbox_folder;
762 src_folder = draft_folder;
764 /* Note: This can fail (with a warning) if the message is not really already in a folder,
765 * because this function requires it to have a UID. */
766 header = tny_msg_get_header (info->draft_msg);
767 tny_folder_remove_msg (src_folder, header, NULL);
769 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
770 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
772 g_object_unref (header);
773 g_object_unref (folder);
780 g_object_unref (info->draft_msg);
782 g_object_unref (draft_folder);
784 g_object_unref (outbox_folder);
785 if (info->transport_account)
786 g_object_unref (info->transport_account);
787 g_slice_free (SendNewMailInfo, info);
788 modest_mail_operation_notify_end (self);
792 modest_mail_operation_send_new_mail (ModestMailOperation *self,
793 TnyTransportAccount *transport_account,
795 const gchar *from, const gchar *to,
796 const gchar *cc, const gchar *bcc,
797 const gchar *subject, const gchar *plain_body,
798 const gchar *html_body,
799 const GList *attachments_list,
800 const GList *images_list,
801 TnyHeaderFlags priority_flags)
803 ModestMailOperationPrivate *priv = NULL;
804 SendNewMailInfo *info;
806 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
807 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
809 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
810 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
812 /* Check parametters */
814 /* Set status failed and set an error */
815 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
816 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
817 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
818 _("Error trying to send a mail. You need to set at least one recipient"));
821 info = g_slice_new0 (SendNewMailInfo);
822 info->transport_account = transport_account;
823 if (transport_account)
824 g_object_ref (transport_account);
825 info->draft_msg = draft_msg;
827 g_object_ref (draft_msg);
830 modest_mail_operation_notify_start (self);
831 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
832 attachments_list, images_list, priority_flags,
833 modest_mail_operation_send_new_mail_cb, info);
839 TnyTransportAccount *transport_account;
841 ModestMsgEditWindow *edit_window;
845 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
849 TnyFolder *src_folder = NULL;
850 TnyFolder *drafts = NULL;
851 TnyHeader *header = NULL;
852 ModestMailOperationPrivate *priv = NULL;
853 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
855 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
858 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
859 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
860 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
861 "modest: failed to create a new msg\n");
865 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
866 TNY_FOLDER_TYPE_DRAFTS);
868 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
869 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
870 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
871 "modest: failed to create a new msg\n");
876 tny_folder_add_msg (drafts, msg, &(priv->error));
878 if ((!priv->error) && (info->draft_msg != NULL)) {
879 header = tny_msg_get_header (info->draft_msg);
880 src_folder = tny_header_get_folder (header);
882 /* Remove the old draft */
883 tny_folder_remove_msg (src_folder, header, NULL);
885 /* Synchronize to expunge and to update the msg counts */
886 tny_folder_sync_async (drafts, TRUE, NULL, NULL, NULL);
887 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
889 g_object_unref (header);
893 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
895 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
897 if (info->edit_window)
898 modest_msg_edit_window_set_draft (info->edit_window, msg);
903 g_object_unref (G_OBJECT(drafts));
905 g_object_unref (G_OBJECT(src_folder));
906 if (info->edit_window)
907 g_object_unref (G_OBJECT(info->edit_window));
909 g_object_unref (G_OBJECT (info->draft_msg));
910 if (info->transport_account)
911 g_object_unref (G_OBJECT(info->transport_account));
912 g_slice_free (SaveToDraftsInfo, info);
914 modest_mail_operation_notify_end (self);
918 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
919 TnyTransportAccount *transport_account,
921 ModestMsgEditWindow *edit_window,
922 const gchar *from, const gchar *to,
923 const gchar *cc, const gchar *bcc,
924 const gchar *subject, const gchar *plain_body,
925 const gchar *html_body,
926 const GList *attachments_list,
927 const GList *images_list,
928 TnyHeaderFlags priority_flags)
930 ModestMailOperationPrivate *priv = NULL;
931 SaveToDraftsInfo *info = NULL;
933 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
934 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
936 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
938 /* Get account and set it into mail_operation */
939 priv->account = g_object_ref (transport_account);
940 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
942 info = g_slice_new0 (SaveToDraftsInfo);
943 info->transport_account = g_object_ref (transport_account);
944 info->draft_msg = draft_msg;
946 g_object_ref (draft_msg);
947 info->edit_window = edit_window;
949 g_object_ref (edit_window);
951 modest_mail_operation_notify_start (self);
952 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
953 attachments_list, images_list, priority_flags,
954 modest_mail_operation_save_to_drafts_cb, info);
959 ModestMailOperation *mail_op;
960 TnyStoreAccount *account;
961 TnyTransportAccount *transport_account;
964 gchar *retrieve_type;
966 UpdateAccountCallback callback;
968 TnyList *new_headers;
973 ModestMailOperation *mail_op;
974 TnyMimePart *mime_part;
976 GetMimePartSizeCallback callback;
978 } GetMimePartSizeInfo;
980 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
981 /* We use this folder observer to track the headers that have been
982 * added to a folder */
985 TnyList *new_headers;
986 } InternalFolderObserver;
990 } InternalFolderObserverClass;
992 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
994 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
995 internal_folder_observer,
997 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1001 foreach_add_item (gpointer header, gpointer user_data)
1003 tny_list_prepend (TNY_LIST (user_data),
1004 g_object_ref (G_OBJECT (header)));
1007 /* This is the method that looks for new messages in a folder */
1009 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1011 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1013 TnyFolderChangeChanged changed;
1015 changed = tny_folder_change_get_changed (change);
1017 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1020 /* Get added headers */
1021 list = tny_simple_list_new ();
1022 tny_folder_change_get_added_headers (change, list);
1024 /* Add them to the folder observer */
1025 tny_list_foreach (list, foreach_add_item,
1026 derived->new_headers);
1028 g_object_unref (G_OBJECT (list));
1033 internal_folder_observer_init (InternalFolderObserver *self)
1035 self->new_headers = tny_simple_list_new ();
1038 internal_folder_observer_finalize (GObject *object)
1040 InternalFolderObserver *self;
1042 self = (InternalFolderObserver *) object;
1043 g_object_unref (self->new_headers);
1045 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1048 tny_folder_observer_init (TnyFolderObserverIface *iface)
1050 iface->update_func = internal_folder_observer_update;
1053 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1055 GObjectClass *object_class;
1057 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1058 object_class = (GObjectClass*) klass;
1059 object_class->finalize = internal_folder_observer_finalize;
1065 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
1068 TnyList *folders = tny_simple_list_new ();
1070 tny_folder_store_get_folders (store, folders, query, NULL);
1071 iter = tny_list_create_iterator (folders);
1073 while (!tny_iterator_is_done (iter)) {
1075 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1077 tny_list_prepend (all_folders, G_OBJECT (folder));
1078 recurse_folders (folder, query, all_folders);
1079 g_object_unref (G_OBJECT (folder));
1082 tny_iterator_next (iter);
1084 g_object_unref (G_OBJECT (iter));
1085 g_object_unref (G_OBJECT (folders));
1089 * Issues the "progress-changed" signal. The timer won't be removed,
1090 * so you must call g_source_remove to stop the signal emission
1093 idle_notify_progress (gpointer data)
1095 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1096 ModestMailOperationState *state;
1098 state = modest_mail_operation_clone_state (mail_op);
1100 /* This is a GDK lock because we are an idle callback and
1101 * the handlers of this signal can contain Gtk+ code */
1103 gdk_threads_enter (); /* CHECKED */
1104 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1105 gdk_threads_leave (); /* CHECKED */
1107 g_slice_free (ModestMailOperationState, state);
1113 * Issues the "progress-changed" signal and removes the timer. It uses
1114 * a lock to ensure that the progress information of the mail
1115 * operation is not modified while there are notifications pending
1118 idle_notify_progress_once (gpointer data)
1122 pair = (ModestPair *) data;
1124 /* This is a GDK lock because we are an idle callback and
1125 * the handlers of this signal can contain Gtk+ code */
1127 gdk_threads_enter (); /* CHECKED */
1128 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1129 gdk_threads_leave (); /* CHECKED */
1131 /* Free the state and the reference to the mail operation */
1132 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1133 g_object_unref (pair->first);
1139 * Used to notify the queue from the main
1140 * loop. We call it inside an idle call to achieve that
1143 idle_notify_queue (gpointer data)
1145 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1147 /* Do not need to block, the notify end will do it for us */
1148 modest_mail_operation_notify_end (mail_op);
1149 g_object_unref (mail_op);
1155 compare_headers_by_date (gconstpointer a,
1158 TnyHeader **header1, **header2;
1159 time_t sent1, sent2;
1161 header1 = (TnyHeader **) a;
1162 header2 = (TnyHeader **) b;
1164 sent1 = tny_header_get_date_sent (*header1);
1165 sent2 = tny_header_get_date_sent (*header2);
1167 /* We want the most recent ones (greater time_t) at the
1176 set_last_updated_idle (gpointer data)
1179 /* This is a GDK lock because we are an idle callback and
1180 * modest_account_mgr_set_last_updated can issue Gtk+ code */
1182 gdk_threads_enter (); /* CHECKED - please recheck */
1184 /* It does not matter if the time is not exactly the same than
1185 the time when this idle was called, it's just an
1186 approximation and it won't be very different */
1188 modest_account_mgr_set_last_updated (modest_runtime_get_account_mgr (),
1192 gdk_threads_leave (); /* CHECKED - please recheck */
1198 idle_update_account_cb (gpointer data)
1200 UpdateAccountInfo *idle_info;
1202 idle_info = (UpdateAccountInfo *) data;
1204 /* This is a GDK lock because we are an idle callback and
1205 * idle_info->callback can contain Gtk+ code */
1207 gdk_threads_enter (); /* CHECKED */
1208 idle_info->callback (idle_info->mail_op,
1209 idle_info->new_headers,
1210 idle_info->user_data);
1211 gdk_threads_leave (); /* CHECKED */
1214 g_object_unref (idle_info->mail_op);
1215 if (idle_info->new_headers)
1216 g_object_unref (idle_info->new_headers);
1223 get_all_folders_from_account (TnyStoreAccount *account,
1226 TnyList *all_folders = NULL;
1227 TnyIterator *iter = NULL;
1228 TnyFolderStoreQuery *query = NULL;
1230 all_folders = tny_simple_list_new ();
1231 query = tny_folder_store_query_new ();
1232 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1233 tny_folder_store_get_folders (TNY_FOLDER_STORE (account),
1240 g_object_unref (all_folders);
1244 iter = tny_list_create_iterator (all_folders);
1245 while (!tny_iterator_is_done (iter)) {
1246 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1248 recurse_folders (folder, query, all_folders);
1249 g_object_unref (folder);
1251 tny_iterator_next (iter);
1253 g_object_unref (G_OBJECT (iter));
1260 update_account_thread (gpointer thr_user_data)
1262 static gboolean first_time = TRUE;
1263 UpdateAccountInfo *info = NULL;
1264 TnyList *all_folders = NULL, *new_headers = NULL;
1265 GPtrArray *new_headers_array = NULL;
1266 TnyIterator *iter = NULL;
1267 ModestMailOperationPrivate *priv = NULL;
1268 ModestTnySendQueue *send_queue = NULL;
1269 gint i = 0, timeout = 0;
1271 info = (UpdateAccountInfo *) thr_user_data;
1272 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1274 /* Get account and set it into mail_operation */
1275 priv->account = g_object_ref (info->account);
1277 /* Get all the folders. We can do it synchronously because
1278 we're already running in a different thread than the UI */
1279 all_folders = get_all_folders_from_account (info->account, &(priv->error));
1281 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1285 /* Update status and notify. We need to call the notification
1286 with a source function in order to call it from the main
1287 loop. We need that in order not to get into trouble with
1288 Gtk+. We use a timeout in order to provide more status
1289 information, because the sync tinymail call does not
1290 provide it for the moment */
1291 timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1293 new_headers_array = g_ptr_array_new ();
1294 iter = tny_list_create_iterator (all_folders);
1296 while (!tny_iterator_is_done (iter) && !priv->error &&
1297 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1299 TnyFolderType folder_type;
1300 TnyFolder *folder = NULL;
1302 folder = TNY_FOLDER (tny_iterator_get_current (iter));
1303 folder_type = tny_folder_get_folder_type (folder);
1305 /* Refresh it only if it's the INBOX */
1306 if (folder_type == TNY_FOLDER_TYPE_INBOX) {
1307 InternalFolderObserver *observer = NULL;
1308 TnyIterator *new_headers_iter = NULL;
1310 /* Refresh the folder. Our observer receives
1311 * the new emails during folder refreshes, so
1312 * we can use observer->new_headers
1314 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1315 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1317 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1319 new_headers_iter = tny_list_create_iterator (observer->new_headers);
1320 while (!tny_iterator_is_done (new_headers_iter)) {
1321 TnyHeader *header = NULL;
1323 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1324 /* Apply per-message size limits */
1325 if (tny_header_get_message_size (header) < info->max_size)
1326 g_ptr_array_add (new_headers_array, g_object_ref (header));
1328 g_object_unref (header);
1329 tny_iterator_next (new_headers_iter);
1331 g_object_unref (new_headers_iter);
1333 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1334 g_object_unref (observer);
1336 /* We no not need to do it the first time,
1337 because it's automatically done by the tree
1339 if (G_LIKELY (!first_time))
1340 tny_folder_poke_status (folder);
1342 g_object_unref (folder);
1344 tny_iterator_next (iter);
1346 g_object_unref (G_OBJECT (iter));
1347 g_source_remove (timeout);
1349 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1350 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1351 new_headers_array->len > 0) {
1355 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1357 /* TODO: Ask the user, instead of just failing,
1358 * showing mail_nc_msg_count_limit_exceeded, with 'Get
1359 * all' and 'Newest only' buttons. */
1360 if (new_headers_array->len > info->retrieve_limit) {
1364 /* Should be get only the headers or the message as well? */
1365 if (g_ascii_strcasecmp (info->retrieve_type,
1366 MODEST_ACCOUNT_RETRIEVE_VALUE_HEADERS_ONLY) != 0) {
1368 priv->total = MIN (new_headers_array->len, info->retrieve_limit);
1369 while (msg_num < priv->total) {
1371 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1372 TnyFolder *folder = tny_header_get_folder (header);
1373 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1374 ModestMailOperationState *state;
1378 /* We can not just use the mail operation because the
1379 values of done and total could change before the
1381 state = modest_mail_operation_clone_state (info->mail_op);
1382 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1383 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1384 pair, (GDestroyNotify) modest_pair_free);
1386 g_object_unref (msg);
1387 g_object_unref (folder);
1394 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1397 /* Copy the headers to a list and free the array */
1398 new_headers = tny_simple_list_new ();
1399 for (i=0; i < new_headers_array->len; i++) {
1400 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1401 tny_list_append (new_headers, G_OBJECT (header));
1403 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1404 g_ptr_array_free (new_headers_array, FALSE);
1407 /* Perform send (if operation was not cancelled) */
1410 if (priv->account != NULL)
1411 g_object_unref (priv->account);
1413 if (info->transport_account) {
1414 priv->account = g_object_ref (info->transport_account);
1416 send_queue = modest_runtime_get_send_queue (info->transport_account);
1418 modest_tny_send_queue_try_to_send (send_queue);
1420 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1421 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1422 "cannot create a send queue for %s\n",
1423 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1424 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1428 /* Check if the operation was a success */
1430 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1432 /* Update the last updated key */
1433 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1434 set_last_updated_idle,
1435 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1436 (GDestroyNotify) g_free);
1440 /* Set the account back to not busy */
1441 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
1442 info->account_name, FALSE);
1444 if (info->callback) {
1445 UpdateAccountInfo *idle_info;
1447 /* This thread is not in the main lock */
1448 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1449 idle_info->mail_op = g_object_ref (info->mail_op);
1450 idle_info->new_headers = (new_headers) ? g_object_ref (new_headers) : NULL;
1451 idle_info->callback = info->callback;
1452 idle_info->user_data = info->user_data;
1453 g_idle_add (idle_update_account_cb, idle_info);
1456 /* Notify about operation end. Note that the info could be
1457 freed before this idle happens, but the mail operation will
1459 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1463 g_object_unref (new_headers);
1465 g_object_unref (all_folders);
1466 g_object_unref (info->account);
1467 if (info->transport_account)
1468 g_object_unref (info->transport_account);
1469 g_free (info->account_name);
1470 g_free (info->retrieve_type);
1471 g_slice_free (UpdateAccountInfo, info);
1479 modest_mail_operation_update_account (ModestMailOperation *self,
1480 const gchar *account_name,
1481 UpdateAccountCallback callback,
1484 GThread *thread = NULL;
1485 UpdateAccountInfo *info = NULL;
1486 ModestMailOperationPrivate *priv = NULL;
1487 ModestAccountMgr *mgr = NULL;
1488 TnyStoreAccount *store_account = NULL;
1489 TnyTransportAccount *transport_account = NULL;
1491 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1492 g_return_val_if_fail (account_name, FALSE);
1494 /* Init mail operation. Set total and done to 0, and do not
1495 update them, this way the progress objects will know that
1496 we have no clue about the number of the objects */
1497 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1500 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1501 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1503 /* Get the store account */
1504 store_account = (TnyStoreAccount *)
1505 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1507 TNY_ACCOUNT_TYPE_STORE);
1509 if (!store_account) {
1510 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1511 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1512 "cannot get tny store account for %s\n", account_name);
1517 /* Get the transport account, we can not do it in the thread
1518 due to some problems with dbus */
1519 transport_account = (TnyTransportAccount *)
1520 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1522 if (!transport_account) {
1523 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1524 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1525 "cannot get tny transport account for %s\n", account_name);
1529 /* Create the helper object */
1530 info = g_slice_new (UpdateAccountInfo);
1531 info->mail_op = self;
1532 info->account = store_account;
1533 info->transport_account = transport_account;
1534 info->callback = callback;
1535 info->account_name = g_strdup (account_name);
1536 info->user_data = user_data;
1538 /* Get the message size limit */
1539 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1540 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1541 if (info->max_size == 0)
1542 info->max_size = G_MAXINT;
1544 info->max_size = info->max_size * KB;
1546 /* Get per-account retrieval type */
1547 mgr = modest_runtime_get_account_mgr ();
1548 info->retrieve_type = modest_account_mgr_get_retrieve_type (mgr, account_name);
1550 /* Get per-account message amount retrieval limit */
1551 info->retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, account_name);
1552 if (info->retrieve_limit == 0)
1553 info->retrieve_limit = G_MAXINT;
1555 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1557 /* Set account busy */
1558 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1560 modest_mail_operation_notify_start (self);
1561 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1567 g_object_unref (store_account);
1568 if (transport_account)
1569 g_object_unref (transport_account);
1570 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1572 callback (self, NULL, user_data);
1574 modest_mail_operation_notify_end (self);
1578 /* ******************************************************************* */
1579 /* ************************** STORE ACTIONS ************************* */
1580 /* ******************************************************************* */
1584 modest_mail_operation_create_folder (ModestMailOperation *self,
1585 TnyFolderStore *parent,
1588 ModestMailOperationPrivate *priv;
1589 TnyFolder *new_folder = NULL;
1591 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1592 g_return_val_if_fail (name, NULL);
1594 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1595 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1597 /* Check for already existing folder */
1598 if (modest_tny_folder_has_subfolder_with_name (parent, name)) {
1599 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1600 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1601 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1602 _CS("ckdg_ib_folder_already_exists"));
1606 if (TNY_IS_FOLDER (parent)) {
1607 /* Check folder rules */
1608 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1609 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1610 /* Set status failed and set an error */
1611 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1612 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1613 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1614 _("mail_in_ui_folder_create_error"));
1618 if (!strcmp (name, " ") || strchr (name, '/')) {
1619 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1620 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1621 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1622 _("mail_in_ui_folder_create_error"));
1626 /* Create the folder */
1627 modest_mail_operation_notify_start (self);
1628 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1629 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1631 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1634 /* Notify about operation end */
1635 modest_mail_operation_notify_end (self);
1641 modest_mail_operation_remove_folder (ModestMailOperation *self,
1643 gboolean remove_to_trash)
1645 TnyAccount *account;
1646 ModestMailOperationPrivate *priv;
1647 ModestTnyFolderRules rules;
1649 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1650 g_return_if_fail (TNY_IS_FOLDER (folder));
1652 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1654 /* Check folder rules */
1655 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1656 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1657 /* Set status failed and set an error */
1658 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1659 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1660 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1661 _("mail_in_ui_folder_delete_error"));
1665 /* Get the account */
1666 account = modest_tny_folder_get_account (folder);
1667 priv->account = g_object_ref(account);
1668 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1670 /* Delete folder or move to trash */
1671 if (remove_to_trash) {
1672 TnyFolder *trash_folder = NULL;
1673 trash_folder = modest_tny_account_get_special_folder (account,
1674 TNY_FOLDER_TYPE_TRASH);
1675 /* TODO: error_handling */
1677 modest_mail_operation_notify_start (self);
1678 modest_mail_operation_xfer_folder (self, folder,
1679 TNY_FOLDER_STORE (trash_folder),
1681 g_object_unref (trash_folder);
1684 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1686 modest_mail_operation_notify_start (self);
1687 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1688 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1691 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1694 g_object_unref (G_OBJECT (parent));
1696 g_object_unref (G_OBJECT (account));
1699 /* Notify about operation end */
1700 modest_mail_operation_notify_end (self);
1704 transfer_folder_status_cb (GObject *obj,
1708 ModestMailOperation *self;
1709 ModestMailOperationPrivate *priv;
1710 ModestMailOperationState *state;
1711 XFerMsgAsyncHelper *helper;
1713 g_return_if_fail (status != NULL);
1714 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1716 helper = (XFerMsgAsyncHelper *) user_data;
1717 g_return_if_fail (helper != NULL);
1719 self = helper->mail_op;
1720 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1722 priv->done = status->position;
1723 priv->total = status->of_total;
1725 state = modest_mail_operation_clone_state (self);
1727 /* This is not a GDK lock because we are a Tinymail callback
1728 * which is already GDK locked by Tinymail */
1730 /* no gdk_threads_enter (), CHECKED */
1732 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1734 /* no gdk_threads_leave (), CHECKED */
1736 g_slice_free (ModestMailOperationState, state);
1741 transfer_folder_cb (TnyFolder *folder,
1743 TnyFolderStore *into,
1744 TnyFolder *new_folder,
1748 XFerMsgAsyncHelper *helper;
1749 ModestMailOperation *self = NULL;
1750 ModestMailOperationPrivate *priv = NULL;
1752 helper = (XFerMsgAsyncHelper *) user_data;
1753 g_return_if_fail (helper != NULL);
1755 self = helper->mail_op;
1756 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1759 priv->error = g_error_copy (err);
1761 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1762 } else if (cancelled) {
1763 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1764 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1765 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1766 _("Transference of %s was cancelled."),
1767 tny_folder_get_name (folder));
1770 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1773 /* Notify about operation end */
1774 modest_mail_operation_notify_end (self);
1776 /* If user defined callback function was defined, call it */
1777 if (helper->user_callback) {
1779 /* This is not a GDK lock because we are a Tinymail callback
1780 * which is already GDK locked by Tinymail */
1782 /* no gdk_threads_enter (), CHECKED */
1783 helper->user_callback (self, helper->user_data);
1784 /* no gdk_threads_leave () , CHECKED */
1788 g_object_unref (helper->mail_op);
1789 g_slice_free (XFerMsgAsyncHelper, helper);
1794 * This function checks if the new name is a valid name for our local
1795 * folders account. The new name could not be the same than then name
1796 * of any of the mandatory local folders
1798 * We can not rely on tinymail because tinymail does not check the
1799 * name of the virtual folders that the account could have in the case
1800 * that we're doing a rename (because it directly calls Camel which
1801 * knows nothing about our virtual folders).
1803 * In the case of an actual copy/move (i.e. move/copy a folder between
1804 * accounts) tinymail uses the tny_folder_store_create_account which
1805 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1806 * checks the new name of the folder, so this call in that case
1807 * wouldn't be needed. *But* NOTE that if tinymail changes its
1808 * implementation (if folder transfers within the same account is no
1809 * longer implemented as a rename) this call will allow Modest to work
1812 * If the new name is not valid, this function will set the status to
1813 * failed and will set also an error in the mail operation
1816 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1817 TnyFolderStore *into,
1818 const gchar *new_name)
1820 if (TNY_IS_ACCOUNT (into) &&
1821 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1822 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1824 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1825 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1826 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1827 _("ckdg_ib_folder_already_exists"));
1834 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1836 TnyFolderStore *parent,
1837 gboolean delete_original,
1838 XferAsyncUserCallback user_callback,
1841 ModestMailOperationPrivate *priv = NULL;
1842 ModestTnyFolderRules parent_rules = 0, rules;
1843 XFerMsgAsyncHelper *helper = NULL;
1844 const gchar *folder_name = NULL;
1845 const gchar *error_msg;
1847 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1848 g_return_if_fail (TNY_IS_FOLDER (folder));
1849 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1851 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1852 folder_name = tny_folder_get_name (folder);
1854 /* Set the error msg */
1855 error_msg = _("mail_in_ui_folder_move_target_error");
1857 /* Get account and set it into mail_operation */
1858 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1859 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1860 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1862 /* Get folder rules */
1863 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1864 if (TNY_IS_FOLDER (parent))
1865 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1867 /* Apply operation constraints */
1868 if ((gpointer) parent == (gpointer) folder ||
1869 (!TNY_IS_FOLDER_STORE (parent)) ||
1870 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1873 } else if (TNY_IS_FOLDER (parent) &&
1874 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1878 } else if (TNY_IS_FOLDER (parent) &&
1879 TNY_IS_FOLDER_STORE (folder) &&
1880 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1881 TNY_FOLDER_STORE (folder))) {
1882 /* Do not move a parent into a child */
1884 } else if (TNY_IS_FOLDER_STORE (parent) &&
1885 modest_tny_folder_has_subfolder_with_name (parent, folder_name)) {
1886 /* Check that the new folder name is not used by any
1889 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1890 /* Check that the new folder name is not used by any
1891 special local folder */
1894 /* Create the helper */
1895 helper = g_slice_new0 (XFerMsgAsyncHelper);
1896 helper->mail_op = g_object_ref (self);
1897 helper->dest_folder = NULL;
1898 helper->headers = NULL;
1899 helper->user_callback = user_callback;
1900 helper->user_data = user_data;
1902 /* Move/Copy folder */
1903 modest_mail_operation_notify_start (self);
1904 tny_folder_copy_async (folder,
1906 tny_folder_get_name (folder),
1909 transfer_folder_status_cb,
1915 /* Set status failed and set an error */
1916 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1917 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1918 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1921 /* Call the user callback if exists */
1923 user_callback (self, user_data);
1925 /* Notify the queue */
1926 modest_mail_operation_notify_end (self);
1930 modest_mail_operation_rename_folder (ModestMailOperation *self,
1934 ModestMailOperationPrivate *priv;
1935 ModestTnyFolderRules rules;
1936 XFerMsgAsyncHelper *helper;
1938 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1939 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1940 g_return_if_fail (name);
1942 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1944 /* Get account and set it into mail_operation */
1945 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1946 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1948 /* Check folder rules */
1949 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1950 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1951 /* Set status failed and set an error */
1952 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1953 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1954 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1955 _("FIXME: unable to rename"));
1957 /* Notify about operation end */
1958 modest_mail_operation_notify_end (self);
1959 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1960 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1961 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1962 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1963 _("FIXME: unable to rename"));
1964 /* Notify about operation end */
1965 modest_mail_operation_notify_end (self);
1967 TnyFolderStore *into;
1969 into = tny_folder_get_folder_store (folder);
1971 /* Check that the new folder name is not used by any
1972 special local folder */
1973 if (new_name_valid_if_local_account (priv, into, name)) {
1974 /* Create the helper */
1975 helper = g_slice_new0 (XFerMsgAsyncHelper);
1976 helper->mail_op = g_object_ref(self);
1977 helper->dest_folder = NULL;
1978 helper->headers = NULL;
1979 helper->user_callback = NULL;
1980 helper->user_data = NULL;
1982 /* Rename. Camel handles folder subscription/unsubscription */
1983 modest_mail_operation_notify_start (self);
1984 tny_folder_copy_async (folder, into, name, TRUE,
1986 transfer_folder_status_cb,
1989 modest_mail_operation_notify_end (self);
1991 g_object_unref (into);
1995 /* ******************************************************************* */
1996 /* ************************** MSG ACTIONS ************************* */
1997 /* ******************************************************************* */
2000 modest_mail_operation_get_msg (ModestMailOperation *self,
2002 GetMsgAsyncUserCallback user_callback,
2005 GetMsgAsyncHelper *helper = NULL;
2007 ModestMailOperationPrivate *priv;
2009 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2010 g_return_if_fail (TNY_IS_HEADER (header));
2012 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2013 folder = tny_header_get_folder (header);
2015 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2016 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2018 /* Get message from folder */
2020 /* Get account and set it into mail_operation */
2021 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2023 /* Check for cached messages */
2024 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2025 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2027 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2029 helper = g_slice_new0 (GetMsgAsyncHelper);
2030 helper->mail_op = self;
2031 helper->user_callback = user_callback;
2032 helper->user_data = user_data;
2033 helper->header = g_object_ref (header);
2035 // The callback's reference so that the mail op is not
2036 // finalized until the async operation is completed even if
2037 // the user canceled the request meanwhile.
2038 g_object_ref (G_OBJECT (helper->mail_op));
2040 modest_mail_operation_notify_start (self);
2041 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
2043 g_object_unref (G_OBJECT (folder));
2045 /* Set status failed and set an error */
2046 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2047 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2048 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2049 _("Error trying to get a message. No folder found for header"));
2051 /* Notify the queue */
2052 modest_mail_operation_notify_end (self);
2057 get_msg_cb (TnyFolder *folder,
2063 GetMsgAsyncHelper *helper = NULL;
2064 ModestMailOperation *self = NULL;
2065 ModestMailOperationPrivate *priv = NULL;
2067 helper = (GetMsgAsyncHelper *) user_data;
2068 g_return_if_fail (helper != NULL);
2069 self = helper->mail_op;
2070 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2071 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2073 /* Check errors and cancel */
2075 priv->error = g_error_copy (error);
2076 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2077 } else if (cancelled) {
2078 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2079 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2080 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2081 _("Error trying to refresh the contents of %s"),
2082 tny_folder_get_name (folder));
2084 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2087 /* If user defined callback function was defined, call it even
2088 if the operation failed*/
2089 if (helper->user_callback) {
2090 /* This is not a GDK lock because we are a Tinymail callback
2091 * which is already GDK locked by Tinymail */
2093 /* no gdk_threads_enter (), CHECKED */
2094 helper->user_callback (self, helper->header, msg, helper->user_data);
2095 /* no gdk_threads_leave (), CHECKED */
2098 /* Notify about operation end */
2099 modest_mail_operation_notify_end (self);
2101 g_object_unref (helper->mail_op);
2102 g_object_unref (helper->header);
2103 g_slice_free (GetMsgAsyncHelper, helper);
2108 get_msg_status_cb (GObject *obj,
2112 GetMsgAsyncHelper *helper = NULL;
2113 ModestMailOperation *self;
2114 ModestMailOperationPrivate *priv;
2115 ModestMailOperationState *state;
2117 g_return_if_fail (status != NULL);
2118 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2120 helper = (GetMsgAsyncHelper *) user_data;
2121 g_return_if_fail (helper != NULL);
2123 self = helper->mail_op;
2124 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2129 state = modest_mail_operation_clone_state (self);
2130 state->bytes_done = status->position;
2131 state->bytes_total = status->of_total;
2133 /* This is not a GDK lock because we are a Tinymail callback
2134 * which is already GDK locked by Tinymail */
2136 /* no gdk_threads_enter (), CHECKED */
2137 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2138 /* no gdk_threads_leave (), CHECKED */
2140 g_slice_free (ModestMailOperationState, state);
2143 /****************************************************/
2145 ModestMailOperation *mail_op;
2147 GetMsgAsyncUserCallback user_callback;
2149 GDestroyNotify notify;
2153 GetMsgAsyncUserCallback user_callback;
2157 ModestMailOperation *mail_op;
2158 } NotifyGetMsgsInfo;
2162 * Used by get_msgs_full_thread to call the user_callback for each
2163 * message that has been read
2166 notify_get_msgs_full (gpointer data)
2168 NotifyGetMsgsInfo *info;
2170 info = (NotifyGetMsgsInfo *) data;
2172 /* This is a GDK lock because we are an idle callback and
2173 * because info->user_callback can contain Gtk+ code */
2175 gdk_threads_enter (); /* CHECKED */
2176 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2177 gdk_threads_leave (); /* CHECKED */
2179 g_slice_free (NotifyGetMsgsInfo, info);
2185 * Used by get_msgs_full_thread to free al the thread resources and to
2186 * call the destroy function for the passed user_data
2189 get_msgs_full_destroyer (gpointer data)
2191 GetFullMsgsInfo *info;
2193 info = (GetFullMsgsInfo *) data;
2197 /* This is a GDK lock because we are an idle callback and
2198 * because info->notify can contain Gtk+ code */
2200 gdk_threads_enter (); /* CHECKED */
2201 info->notify (info->user_data);
2202 gdk_threads_leave (); /* CHECKED */
2206 g_object_unref (info->headers);
2207 g_slice_free (GetFullMsgsInfo, info);
2213 get_msgs_full_thread (gpointer thr_user_data)
2215 GetFullMsgsInfo *info;
2216 ModestMailOperationPrivate *priv = NULL;
2217 TnyIterator *iter = NULL;
2219 info = (GetFullMsgsInfo *) thr_user_data;
2220 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2222 iter = tny_list_create_iterator (info->headers);
2223 while (!tny_iterator_is_done (iter)) {
2227 header = TNY_HEADER (tny_iterator_get_current (iter));
2228 folder = tny_header_get_folder (header);
2230 /* Check for cached messages */
2231 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2232 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2234 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2236 /* Get message from folder */
2239 /* The callback will call it per each header */
2240 msg = tny_folder_get_msg (folder, header, &(priv->error));
2243 ModestMailOperationState *state;
2248 /* notify progress */
2249 state = modest_mail_operation_clone_state (info->mail_op);
2250 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2251 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2252 pair, (GDestroyNotify) modest_pair_free);
2254 /* The callback is the responsible for
2255 freeing the message */
2256 if (info->user_callback) {
2257 NotifyGetMsgsInfo *info_notify;
2258 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2259 info_notify->user_callback = info->user_callback;
2260 info_notify->mail_op = info->mail_op;
2261 info_notify->header = g_object_ref (header);
2262 info_notify->msg = g_object_ref (msg);
2263 info_notify->user_data = info->user_data;
2264 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2265 notify_get_msgs_full,
2268 g_object_unref (msg);
2271 /* Set status failed and set an error */
2272 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2273 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2274 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2275 "Error trying to get a message. No folder found for header");
2279 g_object_unref (header);
2281 tny_iterator_next (iter);
2284 /* Set operation status */
2285 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2286 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2288 /* Notify about operation end */
2289 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2291 /* Free thread resources. Will be called after all previous idles */
2292 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2298 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2299 TnyList *header_list,
2300 GetMsgAsyncUserCallback user_callback,
2302 GDestroyNotify notify)
2304 TnyHeader *header = NULL;
2305 TnyFolder *folder = NULL;
2307 ModestMailOperationPrivate *priv = NULL;
2308 GetFullMsgsInfo *info = NULL;
2309 gboolean size_ok = TRUE;
2311 TnyIterator *iter = NULL;
2313 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2315 /* Init mail operation */
2316 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2317 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2318 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2320 priv->total = tny_list_get_length(header_list);
2322 /* Get account and set it into mail_operation */
2323 if (tny_list_get_length (header_list) >= 1) {
2324 iter = tny_list_create_iterator (header_list);
2325 header = TNY_HEADER (tny_iterator_get_current (iter));
2327 folder = tny_header_get_folder (header);
2329 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2331 g_object_unref (folder);
2334 g_object_unref (header);
2337 if (tny_list_get_length (header_list) == 1) {
2338 g_object_unref (iter);
2343 /* Get msg size limit */
2344 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2345 MODEST_CONF_MSG_SIZE_LIMIT,
2348 g_clear_error (&(priv->error));
2349 max_size = G_MAXINT;
2351 max_size = max_size * KB;
2354 /* Check message size limits. If there is only one message
2355 always retrieve it */
2357 while (!tny_iterator_is_done (iter) && size_ok) {
2358 header = TNY_HEADER (tny_iterator_get_current (iter));
2360 if (tny_header_get_message_size (header) >= max_size)
2362 g_object_unref (header);
2365 tny_iterator_next (iter);
2367 g_object_unref (iter);
2371 /* Create the info */
2372 info = g_slice_new0 (GetFullMsgsInfo);
2373 info->mail_op = self;
2374 info->user_callback = user_callback;
2375 info->user_data = user_data;
2376 info->headers = g_object_ref (header_list);
2377 info->notify = notify;
2379 modest_mail_operation_notify_start (self);
2380 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2382 /* Set status failed and set an error */
2383 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2384 /* FIXME: the error msg is different for pop */
2385 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2386 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2387 _("emev_ni_ui_imap_msg_size_exceed_error"));
2388 /* Remove from queue and free resources */
2389 modest_mail_operation_notify_end (self);
2397 modest_mail_operation_remove_msg (ModestMailOperation *self,
2399 gboolean remove_to_trash /*ignored*/)
2402 ModestMailOperationPrivate *priv;
2404 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2405 g_return_if_fail (TNY_IS_HEADER (header));
2407 if (remove_to_trash)
2408 g_warning ("remove to trash is not implemented");
2410 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2411 folder = tny_header_get_folder (header);
2413 /* Get account and set it into mail_operation */
2414 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2415 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2416 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2418 /* remove message from folder */
2419 tny_folder_remove_msg (folder, header, &(priv->error));
2421 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2422 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2424 modest_mail_operation_notify_start (self);
2426 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2427 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* FALSE --> don't expunge *\/ */
2428 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2429 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2430 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* TRUE --> dont expunge *\/ */
2431 tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2434 /* tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /\* TRUE --> expunge *\/ */
2435 tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2441 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2443 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2446 g_object_unref (G_OBJECT (folder));
2448 /* Notify about operation end */
2449 modest_mail_operation_notify_end (self);
2453 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2455 gboolean remove_to_trash /*ignored*/)
2458 ModestMailOperationPrivate *priv;
2459 TnyIterator *iter = NULL;
2460 TnyHeader *header = NULL;
2462 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2463 g_return_if_fail (TNY_IS_LIST (headers));
2465 if (remove_to_trash)
2466 g_warning ("remove to trash is not implemented");
2468 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2470 /* Get folder from first header and sync it */
2471 iter = tny_list_create_iterator (headers);
2472 header = TNY_HEADER (tny_iterator_get_current (iter));
2473 folder = tny_header_get_folder (header);
2475 /* Get account and set it into mail_operation */
2476 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2477 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2478 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2480 /* remove message from folder */
2481 modest_mail_operation_notify_start (self);
2483 tny_folder_remove_msgs (folder, headers, &(priv->error));
2485 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2486 TNY_IS_CAMEL_POP_FOLDER (folder))
2487 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> don't expunge */
2490 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2496 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2498 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2501 g_object_unref (header);
2502 g_object_unref (iter);
2503 g_object_unref (G_OBJECT (folder));
2505 /* Notify about operation end */
2506 modest_mail_operation_notify_end (self);
2511 transfer_msgs_status_cb (GObject *obj,
2515 XFerMsgAsyncHelper *helper = NULL;
2516 ModestMailOperation *self;
2517 ModestMailOperationPrivate *priv;
2518 ModestMailOperationState *state;
2521 g_return_if_fail (status != NULL);
2522 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2524 helper = (XFerMsgAsyncHelper *) user_data;
2525 g_return_if_fail (helper != NULL);
2527 self = helper->mail_op;
2528 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2530 priv->done = status->position;
2531 priv->total = status->of_total;
2533 state = modest_mail_operation_clone_state (self);
2535 /* This is not a GDK lock because we are a Tinymail callback and
2536 * Tinymail already acquires the Gdk lock */
2538 /* no gdk_threads_enter (), CHECKED */
2540 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2542 /* no gdk_threads_leave (), CHECKED */
2544 g_slice_free (ModestMailOperationState, state);
2549 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2551 XFerMsgAsyncHelper *helper;
2552 ModestMailOperation *self;
2553 ModestMailOperationPrivate *priv;
2554 TnyIterator *iter = NULL;
2555 TnyHeader *header = NULL;
2557 helper = (XFerMsgAsyncHelper *) user_data;
2558 self = helper->mail_op;
2560 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2563 priv->error = g_error_copy (err);
2565 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2566 } else if (cancelled) {
2567 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2568 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2569 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2570 _("Error trying to refresh the contents of %s"),
2571 tny_folder_get_name (folder));
2574 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2576 /* Update folder counts */
2577 tny_folder_poke_status (folder);
2578 tny_folder_poke_status (helper->dest_folder);
2582 /* Mark headers as deleted and seen */
2583 if ((helper->delete) &&
2584 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2585 iter = tny_list_create_iterator (helper->headers);
2586 while (!tny_iterator_is_done (iter)) {
2587 header = TNY_HEADER (tny_iterator_get_current (iter));
2588 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2589 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2590 g_object_unref (header);
2592 tny_iterator_next (iter);
2598 /* Notify about operation end */
2599 modest_mail_operation_notify_end (self);
2601 /* If user defined callback function was defined, call it */
2602 if (helper->user_callback) {
2603 /* This is not a GDK lock because we are a Tinymail callback and
2604 * Tinymail already acquires the Gdk lock */
2606 /* no gdk_threads_enter (), CHECKED */
2607 helper->user_callback (self, helper->user_data);
2608 /* no gdk_threads_leave (), CHECKED */
2612 if (helper->headers)
2613 g_object_unref (helper->headers);
2614 if (helper->dest_folder)
2615 g_object_unref (helper->dest_folder);
2616 if (helper->mail_op)
2617 g_object_unref (helper->mail_op);
2619 g_object_unref (folder);
2621 g_object_unref (iter);
2622 g_slice_free (XFerMsgAsyncHelper, helper);
2626 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2629 gboolean delete_original,
2630 XferAsyncUserCallback user_callback,
2633 ModestMailOperationPrivate *priv = NULL;
2634 TnyIterator *iter = NULL;
2635 TnyFolder *src_folder = NULL;
2636 XFerMsgAsyncHelper *helper = NULL;
2637 TnyHeader *header = NULL;
2638 ModestTnyFolderRules rules = 0;
2640 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2641 g_return_if_fail (TNY_IS_LIST (headers));
2642 g_return_if_fail (TNY_IS_FOLDER (folder));
2644 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2647 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2648 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2650 /* Apply folder rules */
2651 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2652 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2653 /* Set status failed and set an error */
2654 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2655 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2656 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2657 _CS("ckct_ib_unable_to_paste_here"));
2658 /* Notify the queue */
2659 modest_mail_operation_notify_end (self);
2663 /* Get source folder */
2664 iter = tny_list_create_iterator (headers);
2665 header = TNY_HEADER (tny_iterator_get_current (iter));
2667 src_folder = tny_header_get_folder (header);
2668 g_object_unref (header);
2671 g_object_unref (iter);
2673 /* Check folder source and destination */
2674 if (src_folder == folder) {
2675 /* Set status failed and set an error */
2676 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2677 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2678 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2679 _("mcen_ib_unable_to_copy_samefolder"));
2681 /* Notify the queue */
2682 modest_mail_operation_notify_end (self);
2685 g_object_unref (src_folder);
2689 /* Create the helper */
2690 helper = g_slice_new0 (XFerMsgAsyncHelper);
2691 helper->mail_op = g_object_ref(self);
2692 helper->dest_folder = g_object_ref(folder);
2693 helper->headers = g_object_ref(headers);
2694 helper->user_callback = user_callback;
2695 helper->user_data = user_data;
2696 helper->delete = delete_original;
2698 /* Get account and set it into mail_operation */
2699 priv->account = modest_tny_folder_get_account (src_folder);
2701 /* Transfer messages */
2702 modest_mail_operation_notify_start (self);
2703 tny_folder_transfer_msgs_async (src_folder,
2708 transfer_msgs_status_cb,
2714 on_refresh_folder (TnyFolder *folder,
2719 RefreshAsyncHelper *helper = NULL;
2720 ModestMailOperation *self = NULL;
2721 ModestMailOperationPrivate *priv = NULL;
2723 helper = (RefreshAsyncHelper *) user_data;
2724 self = helper->mail_op;
2725 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2727 g_return_if_fail(priv!=NULL);
2730 priv->error = g_error_copy (error);
2731 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2732 printf("DEBUG: %s: Operation error:\n %s", __FUNCTION__,
2738 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2739 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2740 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2741 _("Error trying to refresh the contents of %s"),
2742 tny_folder_get_name (folder));
2743 printf("DEBUG: %s: Operation cancelled.\n", __FUNCTION__);
2747 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2749 /* Call user defined callback, if it exists */
2750 if (helper->user_callback) {
2752 /* This is not a GDK lock because we are a Tinymail callback and
2753 * Tinymail already acquires the Gdk lock */
2754 helper->user_callback (self, folder, helper->user_data);
2759 g_slice_free (RefreshAsyncHelper, helper);
2761 /* Notify about operation end */
2762 modest_mail_operation_notify_end (self);
2763 g_object_unref(self);
2767 on_refresh_folder_status_update (GObject *obj,
2771 RefreshAsyncHelper *helper = NULL;
2772 ModestMailOperation *self = NULL;
2773 ModestMailOperationPrivate *priv = NULL;
2774 ModestMailOperationState *state;
2776 g_return_if_fail (user_data != NULL);
2777 g_return_if_fail (status != NULL);
2778 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2780 helper = (RefreshAsyncHelper *) user_data;
2781 self = helper->mail_op;
2782 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2784 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2786 priv->done = status->position;
2787 priv->total = status->of_total;
2789 state = modest_mail_operation_clone_state (self);
2791 /* This is not a GDK lock because we are a Tinymail callback and
2792 * Tinymail already acquires the Gdk lock */
2793 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2795 g_slice_free (ModestMailOperationState, state);
2799 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2801 RefreshAsyncUserCallback user_callback,
2804 ModestMailOperationPrivate *priv = NULL;
2805 RefreshAsyncHelper *helper = NULL;
2807 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2809 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2811 /* Get account and set it into mail_operation */
2812 priv->account = modest_tny_folder_get_account (folder);
2813 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2815 /* Create the helper */
2816 helper = g_slice_new0 (RefreshAsyncHelper);
2817 helper->mail_op = g_object_ref(self);
2818 helper->user_callback = user_callback;
2819 helper->user_data = user_data;
2821 /* Refresh the folder. TODO: tinymail could issue a status
2822 updates before the callback call then this could happen. We
2823 must review the design */
2824 modest_mail_operation_notify_start (self);
2825 tny_folder_refresh_async (folder,
2827 on_refresh_folder_status_update,
2833 modest_mail_operation_notify_start (ModestMailOperation *self)
2835 ModestMailOperationPrivate *priv = NULL;
2837 g_return_if_fail (self);
2839 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2841 /* Ensure that all the fields are filled correctly */
2842 g_return_if_fail (priv->account != NULL);
2843 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
2845 /* Notify the observers about the mail operation. We do not
2846 wrapp this emission because we assume that this function is
2847 always called from within the main lock */
2848 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
2853 * It's used by the mail operation queue to notify the observers
2854 * attached to that signal that the operation finished. We need to use
2855 * that because tinymail does not give us the progress of a given
2856 * operation when it finishes (it directly calls the operation
2860 modest_mail_operation_notify_end (ModestMailOperation *self)
2862 ModestMailOperationPrivate *priv = NULL;
2864 g_return_if_fail (self);
2866 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2868 /* Notify the observers about the mail operation end. We do
2869 not wrapp this emission because we assume that this
2870 function is always called from within the main lock */
2871 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
2875 modest_mail_operation_get_account (ModestMailOperation *self)
2877 ModestMailOperationPrivate *priv = NULL;
2879 g_return_val_if_fail (self, NULL);
2881 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2883 return (priv->account) ? g_object_ref (priv->account) : NULL;