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 = g_object_ref (info->mail_op);
672 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
673 idle_info->callback = info->callback;
674 idle_info->userdata = info->userdata;
675 g_idle_add (idle_create_msg_cb, idle_info);
677 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
680 g_object_unref (info->mail_op);
681 g_slice_free (CreateMsgInfo, info);
686 modest_mail_operation_create_msg (ModestMailOperation *self,
687 const gchar *from, const gchar *to,
688 const gchar *cc, const gchar *bcc,
689 const gchar *subject, const gchar *plain_body,
690 const gchar *html_body,
691 const GList *attachments_list,
692 const GList *images_list,
693 TnyHeaderFlags priority_flags,
694 ModestMailOperationCreateMsgCallback callback,
697 CreateMsgInfo *info = NULL;
699 info = g_slice_new0 (CreateMsgInfo);
700 info->mail_op = g_object_ref (self);
702 info->from = g_strdup (from);
703 info->to = g_strdup (to);
704 info->cc = g_strdup (cc);
705 info->bcc = g_strdup (bcc);
706 info->subject = g_strdup (subject);
707 info->plain_body = g_strdup (plain_body);
708 info->html_body = g_strdup (html_body);
709 info->attachments_list = g_list_copy ((GList *) attachments_list);
710 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
711 info->images_list = g_list_copy ((GList *) images_list);
712 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
713 info->priority_flags = priority_flags;
715 info->callback = callback;
716 info->userdata = userdata;
718 g_thread_create (create_msg_thread, info, FALSE, NULL);
723 TnyTransportAccount *transport_account;
728 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
732 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
733 TnyFolder *draft_folder = NULL;
734 TnyFolder *outbox_folder = NULL;
742 /* Call mail operation */
743 modest_mail_operation_send_mail (self, info->transport_account, msg);
745 /* Remove old mail from its source folder */
746 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
747 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_OUTBOX);
748 if (info->draft_msg != NULL) {
749 TnyFolder *folder = NULL;
750 TnyFolder *src_folder = NULL;
751 TnyFolderType folder_type;
752 folder = tny_msg_get_folder (info->draft_msg);
753 if (folder == NULL) goto end;
754 folder_type = modest_tny_folder_guess_folder_type (folder);
755 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
756 src_folder = outbox_folder;
758 src_folder = draft_folder;
760 /* Note: This can fail (with a warning) if the message is not really already in a folder,
761 * because this function requires it to have a UID. */
762 header = tny_msg_get_header (info->draft_msg);
763 tny_folder_remove_msg (src_folder, header, NULL);
765 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
766 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
768 g_object_unref (header);
769 g_object_unref (folder);
776 g_object_unref (info->draft_msg);
778 g_object_unref (draft_folder);
780 g_object_unref (outbox_folder);
781 if (info->transport_account)
782 g_object_unref (info->transport_account);
783 g_slice_free (SendNewMailInfo, info);
784 modest_mail_operation_notify_end (self);
788 modest_mail_operation_send_new_mail (ModestMailOperation *self,
789 TnyTransportAccount *transport_account,
791 const gchar *from, const gchar *to,
792 const gchar *cc, const gchar *bcc,
793 const gchar *subject, const gchar *plain_body,
794 const gchar *html_body,
795 const GList *attachments_list,
796 const GList *images_list,
797 TnyHeaderFlags priority_flags)
799 ModestMailOperationPrivate *priv = NULL;
800 SendNewMailInfo *info;
802 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
803 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
805 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
806 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
807 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
809 /* Check parametters */
811 /* Set status failed and set an error */
812 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
813 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
814 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
815 _("Error trying to send a mail. You need to set at least one recipient"));
818 info = g_slice_new0 (SendNewMailInfo);
819 info->transport_account = transport_account;
820 if (transport_account)
821 g_object_ref (transport_account);
822 info->draft_msg = draft_msg;
824 g_object_ref (draft_msg);
827 modest_mail_operation_notify_start (self);
828 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
829 attachments_list, images_list, priority_flags,
830 modest_mail_operation_send_new_mail_cb, info);
836 TnyTransportAccount *transport_account;
838 SaveToDraftstCallback callback;
843 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
847 TnyFolder *src_folder = NULL;
848 TnyFolder *drafts = NULL;
849 TnyHeader *header = NULL;
850 ModestMailOperationPrivate *priv = NULL;
851 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
853 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
856 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
857 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
858 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
859 "modest: failed to create a new msg\n");
863 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
864 TNY_FOLDER_TYPE_DRAFTS);
866 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
867 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
868 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
869 "modest: failed to create a new msg\n");
874 tny_folder_add_msg (drafts, msg, &(priv->error));
876 if ((!priv->error) && (info->draft_msg != NULL)) {
877 header = tny_msg_get_header (info->draft_msg);
878 src_folder = tny_header_get_folder (header);
880 /* Remove the old draft */
881 tny_folder_remove_msg (src_folder, header, NULL);
883 /* Synchronize to expunge and to update the msg counts */
884 tny_folder_sync_async (drafts, TRUE, NULL, NULL, NULL);
885 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
887 g_object_unref (header);
891 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
893 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
896 /* Call the user callback */
898 info->callback (self, msg, info->user_data);
901 g_object_unref (G_OBJECT(drafts));
903 g_object_unref (G_OBJECT(src_folder));
905 g_object_unref (G_OBJECT (info->draft_msg));
906 if (info->transport_account)
907 g_object_unref (G_OBJECT(info->transport_account));
908 g_slice_free (SaveToDraftsInfo, info);
910 modest_mail_operation_notify_end (self);
914 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
915 TnyTransportAccount *transport_account,
917 const gchar *from, const gchar *to,
918 const gchar *cc, const gchar *bcc,
919 const gchar *subject, const gchar *plain_body,
920 const gchar *html_body,
921 const GList *attachments_list,
922 const GList *images_list,
923 TnyHeaderFlags priority_flags,
924 SaveToDraftstCallback callback,
927 ModestMailOperationPrivate *priv = NULL;
928 SaveToDraftsInfo *info = NULL;
930 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
931 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
933 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
935 /* Get account and set it into mail_operation */
936 priv->account = g_object_ref (transport_account);
937 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
939 info = g_slice_new0 (SaveToDraftsInfo);
940 info->transport_account = g_object_ref (transport_account);
941 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
942 info->callback = callback;
943 info->user_data = user_data;
945 modest_mail_operation_notify_start (self);
946 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
947 attachments_list, images_list, priority_flags,
948 modest_mail_operation_save_to_drafts_cb, info);
953 ModestMailOperation *mail_op;
954 TnyStoreAccount *account;
955 TnyTransportAccount *transport_account;
958 gchar *retrieve_type;
960 UpdateAccountCallback callback;
962 TnyList *new_headers;
967 ModestMailOperation *mail_op;
968 TnyMimePart *mime_part;
970 GetMimePartSizeCallback callback;
972 } GetMimePartSizeInfo;
974 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
975 /* We use this folder observer to track the headers that have been
976 * added to a folder */
979 TnyList *new_headers;
980 } InternalFolderObserver;
984 } InternalFolderObserverClass;
986 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
988 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
989 internal_folder_observer,
991 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
995 foreach_add_item (gpointer header, gpointer user_data)
997 tny_list_prepend (TNY_LIST (user_data),
998 g_object_ref (G_OBJECT (header)));
1001 /* This is the method that looks for new messages in a folder */
1003 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1005 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1007 TnyFolderChangeChanged changed;
1009 changed = tny_folder_change_get_changed (change);
1011 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1014 /* Get added headers */
1015 list = tny_simple_list_new ();
1016 tny_folder_change_get_added_headers (change, list);
1018 /* Add them to the folder observer */
1019 tny_list_foreach (list, foreach_add_item,
1020 derived->new_headers);
1022 g_object_unref (G_OBJECT (list));
1027 internal_folder_observer_init (InternalFolderObserver *self)
1029 self->new_headers = tny_simple_list_new ();
1032 internal_folder_observer_finalize (GObject *object)
1034 InternalFolderObserver *self;
1036 self = (InternalFolderObserver *) object;
1037 g_object_unref (self->new_headers);
1039 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1042 tny_folder_observer_init (TnyFolderObserverIface *iface)
1044 iface->update_func = internal_folder_observer_update;
1047 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1049 GObjectClass *object_class;
1051 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1052 object_class = (GObjectClass*) klass;
1053 object_class->finalize = internal_folder_observer_finalize;
1059 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
1062 TnyList *folders = tny_simple_list_new ();
1064 tny_folder_store_get_folders (store, folders, query, NULL);
1065 iter = tny_list_create_iterator (folders);
1067 while (!tny_iterator_is_done (iter)) {
1069 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1071 tny_list_prepend (all_folders, G_OBJECT (folder));
1072 recurse_folders (folder, query, all_folders);
1073 g_object_unref (G_OBJECT (folder));
1076 tny_iterator_next (iter);
1078 g_object_unref (G_OBJECT (iter));
1079 g_object_unref (G_OBJECT (folders));
1083 * Issues the "progress-changed" signal. The timer won't be removed,
1084 * so you must call g_source_remove to stop the signal emission
1087 idle_notify_progress (gpointer data)
1089 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1090 ModestMailOperationState *state;
1092 state = modest_mail_operation_clone_state (mail_op);
1094 /* This is a GDK lock because we are an idle callback and
1095 * the handlers of this signal can contain Gtk+ code */
1097 gdk_threads_enter (); /* CHECKED */
1098 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1099 gdk_threads_leave (); /* CHECKED */
1101 g_slice_free (ModestMailOperationState, state);
1107 * Issues the "progress-changed" signal and removes the timer. It uses
1108 * a lock to ensure that the progress information of the mail
1109 * operation is not modified while there are notifications pending
1112 idle_notify_progress_once (gpointer data)
1116 pair = (ModestPair *) data;
1118 /* This is a GDK lock because we are an idle callback and
1119 * the handlers of this signal can contain Gtk+ code */
1121 gdk_threads_enter (); /* CHECKED */
1122 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1123 gdk_threads_leave (); /* CHECKED */
1125 /* Free the state and the reference to the mail operation */
1126 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1127 g_object_unref (pair->first);
1133 * Used to notify the queue from the main
1134 * loop. We call it inside an idle call to achieve that
1137 idle_notify_queue (gpointer data)
1139 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1141 /* Do not need to block, the notify end will do it for us */
1142 modest_mail_operation_notify_end (mail_op);
1143 g_object_unref (mail_op);
1149 compare_headers_by_date (gconstpointer a,
1152 TnyHeader **header1, **header2;
1153 time_t sent1, sent2;
1155 header1 = (TnyHeader **) a;
1156 header2 = (TnyHeader **) b;
1158 sent1 = tny_header_get_date_sent (*header1);
1159 sent2 = tny_header_get_date_sent (*header2);
1161 /* We want the most recent ones (greater time_t) at the
1170 set_last_updated_idle (gpointer data)
1173 /* This is a GDK lock because we are an idle callback and
1174 * modest_account_mgr_set_last_updated can issue Gtk+ code */
1176 gdk_threads_enter (); /* CHECKED - please recheck */
1178 /* It does not matter if the time is not exactly the same than
1179 the time when this idle was called, it's just an
1180 approximation and it won't be very different */
1182 modest_account_mgr_set_last_updated (modest_runtime_get_account_mgr (),
1186 gdk_threads_leave (); /* CHECKED - please recheck */
1192 idle_update_account_cb (gpointer data)
1194 UpdateAccountInfo *idle_info;
1196 idle_info = (UpdateAccountInfo *) data;
1198 /* This is a GDK lock because we are an idle callback and
1199 * idle_info->callback can contain Gtk+ code */
1201 gdk_threads_enter (); /* CHECKED */
1202 idle_info->callback (idle_info->mail_op,
1203 idle_info->new_headers,
1204 idle_info->user_data);
1205 gdk_threads_leave (); /* CHECKED */
1208 g_object_unref (idle_info->mail_op);
1209 if (idle_info->new_headers)
1210 g_object_unref (idle_info->new_headers);
1217 get_all_folders_from_account (TnyStoreAccount *account,
1220 TnyList *all_folders = NULL;
1221 TnyIterator *iter = NULL;
1222 TnyFolderStoreQuery *query = NULL;
1224 all_folders = tny_simple_list_new ();
1225 query = tny_folder_store_query_new ();
1226 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1227 tny_folder_store_get_folders (TNY_FOLDER_STORE (account),
1234 g_object_unref (all_folders);
1238 iter = tny_list_create_iterator (all_folders);
1239 while (!tny_iterator_is_done (iter)) {
1240 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1242 recurse_folders (folder, query, all_folders);
1243 g_object_unref (folder);
1245 tny_iterator_next (iter);
1247 g_object_unref (G_OBJECT (iter));
1254 update_account_thread (gpointer thr_user_data)
1256 static gboolean first_time = TRUE;
1257 UpdateAccountInfo *info = NULL;
1258 TnyList *all_folders = NULL, *new_headers = NULL;
1259 GPtrArray *new_headers_array = NULL;
1260 TnyIterator *iter = NULL;
1261 ModestMailOperationPrivate *priv = NULL;
1262 ModestTnySendQueue *send_queue = NULL;
1263 gint i = 0, timeout = 0;
1265 info = (UpdateAccountInfo *) thr_user_data;
1266 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1268 /* Get account and set it into mail_operation */
1269 priv->account = g_object_ref (info->account);
1271 /* Get all the folders. We can do it synchronously because
1272 we're already running in a different thread than the UI */
1273 all_folders = get_all_folders_from_account (info->account, &(priv->error));
1275 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1279 /* Update status and notify. We need to call the notification
1280 with a source function in order to call it from the main
1281 loop. We need that in order not to get into trouble with
1282 Gtk+. We use a timeout in order to provide more status
1283 information, because the sync tinymail call does not
1284 provide it for the moment */
1285 timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1287 new_headers_array = g_ptr_array_new ();
1288 iter = tny_list_create_iterator (all_folders);
1290 while (!tny_iterator_is_done (iter) && !priv->error &&
1291 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1293 TnyFolderType folder_type;
1294 TnyFolder *folder = NULL;
1296 folder = TNY_FOLDER (tny_iterator_get_current (iter));
1297 folder_type = tny_folder_get_folder_type (folder);
1299 /* Refresh it only if it's the INBOX */
1300 if (folder_type == TNY_FOLDER_TYPE_INBOX) {
1301 InternalFolderObserver *observer = NULL;
1302 TnyIterator *new_headers_iter = NULL;
1304 /* Refresh the folder. Our observer receives
1305 * the new emails during folder refreshes, so
1306 * we can use observer->new_headers
1308 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1309 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1311 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1313 new_headers_iter = tny_list_create_iterator (observer->new_headers);
1314 while (!tny_iterator_is_done (new_headers_iter)) {
1315 TnyHeader *header = NULL;
1317 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1318 /* Apply per-message size limits */
1319 if (tny_header_get_message_size (header) < info->max_size)
1320 g_ptr_array_add (new_headers_array, g_object_ref (header));
1322 g_object_unref (header);
1323 tny_iterator_next (new_headers_iter);
1325 g_object_unref (new_headers_iter);
1327 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1328 g_object_unref (observer);
1330 /* We no not need to do it the first time,
1331 because it's automatically done by the tree
1333 if (G_LIKELY (!first_time))
1334 tny_folder_poke_status (folder);
1336 g_object_unref (folder);
1338 tny_iterator_next (iter);
1340 g_object_unref (G_OBJECT (iter));
1341 g_source_remove (timeout);
1343 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1344 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1345 new_headers_array->len > 0) {
1349 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1351 /* TODO: Ask the user, instead of just failing,
1352 * showing mail_nc_msg_count_limit_exceeded, with 'Get
1353 * all' and 'Newest only' buttons. */
1354 if (new_headers_array->len > info->retrieve_limit) {
1358 /* Should be get only the headers or the message as well? */
1359 if (g_ascii_strcasecmp (info->retrieve_type,
1360 MODEST_ACCOUNT_RETRIEVE_VALUE_HEADERS_ONLY) != 0) {
1362 priv->total = MIN (new_headers_array->len, info->retrieve_limit);
1363 while (msg_num < priv->total) {
1365 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1366 TnyFolder *folder = tny_header_get_folder (header);
1367 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1368 ModestMailOperationState *state;
1372 /* We can not just use the mail operation because the
1373 values of done and total could change before the
1375 state = modest_mail_operation_clone_state (info->mail_op);
1376 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1377 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1378 pair, (GDestroyNotify) modest_pair_free);
1380 g_object_unref (msg);
1381 g_object_unref (folder);
1388 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1391 /* Copy the headers to a list and free the array */
1392 new_headers = tny_simple_list_new ();
1393 for (i=0; i < new_headers_array->len; i++) {
1394 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1395 tny_list_append (new_headers, G_OBJECT (header));
1397 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1398 g_ptr_array_free (new_headers_array, FALSE);
1401 /* Perform send (if operation was not cancelled) */
1404 if (priv->account != NULL)
1405 g_object_unref (priv->account);
1407 if (info->transport_account) {
1408 priv->account = g_object_ref (info->transport_account);
1410 send_queue = modest_runtime_get_send_queue (info->transport_account);
1412 modest_tny_send_queue_try_to_send (send_queue);
1414 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1415 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1416 "cannot create a send queue for %s\n",
1417 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1418 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1422 /* Check if the operation was a success */
1424 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1426 /* Update the last updated key */
1427 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1428 set_last_updated_idle,
1429 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1430 (GDestroyNotify) g_free);
1434 /* Set the account back to not busy */
1435 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
1436 info->account_name, FALSE);
1438 if (info->callback) {
1439 UpdateAccountInfo *idle_info;
1441 /* This thread is not in the main lock */
1442 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1443 idle_info->mail_op = g_object_ref (info->mail_op);
1444 idle_info->new_headers = (new_headers) ? g_object_ref (new_headers) : NULL;
1445 idle_info->callback = info->callback;
1446 idle_info->user_data = info->user_data;
1447 g_idle_add (idle_update_account_cb, idle_info);
1450 /* Notify about operation end. Note that the info could be
1451 freed before this idle happens, but the mail operation will
1453 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1457 g_object_unref (new_headers);
1459 g_object_unref (all_folders);
1460 g_object_unref (info->account);
1461 if (info->transport_account)
1462 g_object_unref (info->transport_account);
1463 g_free (info->account_name);
1464 g_free (info->retrieve_type);
1465 g_slice_free (UpdateAccountInfo, info);
1473 modest_mail_operation_update_account (ModestMailOperation *self,
1474 const gchar *account_name,
1475 UpdateAccountCallback callback,
1478 GThread *thread = NULL;
1479 UpdateAccountInfo *info = NULL;
1480 ModestMailOperationPrivate *priv = NULL;
1481 ModestAccountMgr *mgr = NULL;
1482 TnyStoreAccount *store_account = NULL;
1483 TnyTransportAccount *transport_account = NULL;
1485 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1486 g_return_val_if_fail (account_name, FALSE);
1488 /* Init mail operation. Set total and done to 0, and do not
1489 update them, this way the progress objects will know that
1490 we have no clue about the number of the objects */
1491 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1494 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1495 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1497 /* Get the store account */
1498 store_account = (TnyStoreAccount *)
1499 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1501 TNY_ACCOUNT_TYPE_STORE);
1503 if (!store_account) {
1504 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1505 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1506 "cannot get tny store account for %s\n", account_name);
1510 priv->account = g_object_ref (store_account);
1512 /* Get the transport account, we can not do it in the thread
1513 due to some problems with dbus */
1514 transport_account = (TnyTransportAccount *)
1515 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1517 if (!transport_account) {
1518 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1519 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1520 "cannot get tny transport account for %s\n", account_name);
1524 /* Create the helper object */
1525 info = g_slice_new (UpdateAccountInfo);
1526 info->mail_op = self;
1527 info->account = store_account;
1528 info->transport_account = transport_account;
1529 info->callback = callback;
1530 info->account_name = g_strdup (account_name);
1531 info->user_data = user_data;
1533 /* Get the message size limit */
1534 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1535 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1536 if (info->max_size == 0)
1537 info->max_size = G_MAXINT;
1539 info->max_size = info->max_size * KB;
1541 /* Get per-account retrieval type */
1542 mgr = modest_runtime_get_account_mgr ();
1543 info->retrieve_type = modest_account_mgr_get_retrieve_type (mgr, account_name);
1545 /* Get per-account message amount retrieval limit */
1546 info->retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, account_name);
1547 if (info->retrieve_limit == 0)
1548 info->retrieve_limit = G_MAXINT;
1550 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1552 /* Set account busy */
1553 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1555 modest_mail_operation_notify_start (self);
1556 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1562 g_object_unref (store_account);
1563 if (transport_account)
1564 g_object_unref (transport_account);
1565 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1567 callback (self, NULL, user_data);
1569 modest_mail_operation_notify_end (self);
1573 /* ******************************************************************* */
1574 /* ************************** STORE ACTIONS ************************* */
1575 /* ******************************************************************* */
1579 modest_mail_operation_create_folder (ModestMailOperation *self,
1580 TnyFolderStore *parent,
1583 ModestMailOperationPrivate *priv;
1584 TnyFolder *new_folder = NULL;
1586 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1587 g_return_val_if_fail (name, NULL);
1589 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1590 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1591 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1592 g_object_ref (parent) :
1593 modest_tny_folder_get_account (TNY_FOLDER (parent));
1595 /* Check for already existing folder */
1596 if (modest_tny_folder_has_subfolder_with_name (parent, name)) {
1597 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1598 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1599 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1600 _CS("ckdg_ib_folder_already_exists"));
1604 if (TNY_IS_FOLDER (parent)) {
1605 /* Check folder rules */
1606 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1607 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1608 /* Set status failed and set an error */
1609 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1610 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1611 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1612 _("mail_in_ui_folder_create_error"));
1616 if (!strcmp (name, " ") || strchr (name, '/')) {
1617 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1618 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1619 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1620 _("mail_in_ui_folder_create_error"));
1624 /* Create the folder */
1625 modest_mail_operation_notify_start (self);
1626 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1627 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1629 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1632 /* Notify about operation end */
1633 modest_mail_operation_notify_end (self);
1639 modest_mail_operation_remove_folder (ModestMailOperation *self,
1641 gboolean remove_to_trash)
1643 TnyAccount *account;
1644 ModestMailOperationPrivate *priv;
1645 ModestTnyFolderRules rules;
1647 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1648 g_return_if_fail (TNY_IS_FOLDER (folder));
1650 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1652 /* Check folder rules */
1653 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1654 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1655 /* Set status failed and set an error */
1656 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1657 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1658 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1659 _("mail_in_ui_folder_delete_error"));
1663 /* Get the account */
1664 account = modest_tny_folder_get_account (folder);
1665 priv->account = g_object_ref(account);
1666 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1668 /* Delete folder or move to trash */
1669 if (remove_to_trash) {
1670 TnyFolder *trash_folder = NULL;
1671 trash_folder = modest_tny_account_get_special_folder (account,
1672 TNY_FOLDER_TYPE_TRASH);
1673 /* TODO: error_handling */
1675 modest_mail_operation_notify_start (self);
1676 modest_mail_operation_xfer_folder (self, folder,
1677 TNY_FOLDER_STORE (trash_folder),
1679 g_object_unref (trash_folder);
1682 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1684 modest_mail_operation_notify_start (self);
1685 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1686 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1689 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1692 g_object_unref (G_OBJECT (parent));
1694 g_object_unref (G_OBJECT (account));
1697 /* Notify about operation end */
1698 modest_mail_operation_notify_end (self);
1702 transfer_folder_status_cb (GObject *obj,
1706 ModestMailOperation *self;
1707 ModestMailOperationPrivate *priv;
1708 ModestMailOperationState *state;
1709 XFerMsgAsyncHelper *helper;
1711 g_return_if_fail (status != NULL);
1712 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1714 helper = (XFerMsgAsyncHelper *) user_data;
1715 g_return_if_fail (helper != NULL);
1717 self = helper->mail_op;
1718 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1720 priv->done = status->position;
1721 priv->total = status->of_total;
1723 state = modest_mail_operation_clone_state (self);
1725 /* This is not a GDK lock because we are a Tinymail callback
1726 * which is already GDK locked by Tinymail */
1728 /* no gdk_threads_enter (), CHECKED */
1730 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1732 /* no gdk_threads_leave (), CHECKED */
1734 g_slice_free (ModestMailOperationState, state);
1739 transfer_folder_cb (TnyFolder *folder,
1741 TnyFolderStore *into,
1742 TnyFolder *new_folder,
1746 XFerMsgAsyncHelper *helper;
1747 ModestMailOperation *self = NULL;
1748 ModestMailOperationPrivate *priv = NULL;
1750 helper = (XFerMsgAsyncHelper *) user_data;
1751 g_return_if_fail (helper != NULL);
1753 self = helper->mail_op;
1754 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1757 priv->error = g_error_copy (err);
1759 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1760 } else if (cancelled) {
1761 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1762 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1763 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1764 _("Transference of %s was cancelled."),
1765 tny_folder_get_name (folder));
1768 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1771 /* Notify about operation end */
1772 modest_mail_operation_notify_end (self);
1774 /* If user defined callback function was defined, call it */
1775 if (helper->user_callback) {
1777 /* This is not a GDK lock because we are a Tinymail callback
1778 * which is already GDK locked by Tinymail */
1780 /* no gdk_threads_enter (), CHECKED */
1781 helper->user_callback (self, helper->user_data);
1782 /* no gdk_threads_leave () , CHECKED */
1786 g_object_unref (helper->mail_op);
1787 g_slice_free (XFerMsgAsyncHelper, helper);
1792 * This function checks if the new name is a valid name for our local
1793 * folders account. The new name could not be the same than then name
1794 * of any of the mandatory local folders
1796 * We can not rely on tinymail because tinymail does not check the
1797 * name of the virtual folders that the account could have in the case
1798 * that we're doing a rename (because it directly calls Camel which
1799 * knows nothing about our virtual folders).
1801 * In the case of an actual copy/move (i.e. move/copy a folder between
1802 * accounts) tinymail uses the tny_folder_store_create_account which
1803 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1804 * checks the new name of the folder, so this call in that case
1805 * wouldn't be needed. *But* NOTE that if tinymail changes its
1806 * implementation (if folder transfers within the same account is no
1807 * longer implemented as a rename) this call will allow Modest to work
1810 * If the new name is not valid, this function will set the status to
1811 * failed and will set also an error in the mail operation
1814 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1815 TnyFolderStore *into,
1816 const gchar *new_name)
1818 if (TNY_IS_ACCOUNT (into) &&
1819 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1820 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1822 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1823 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1824 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1825 _("ckdg_ib_folder_already_exists"));
1832 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1834 TnyFolderStore *parent,
1835 gboolean delete_original,
1836 XferAsyncUserCallback user_callback,
1839 ModestMailOperationPrivate *priv = NULL;
1840 ModestTnyFolderRules parent_rules = 0, rules;
1841 XFerMsgAsyncHelper *helper = NULL;
1842 const gchar *folder_name = NULL;
1843 const gchar *error_msg;
1845 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1846 g_return_if_fail (TNY_IS_FOLDER (folder));
1847 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1849 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1850 folder_name = tny_folder_get_name (folder);
1852 /* Set the error msg */
1853 error_msg = _("mail_in_ui_folder_move_target_error");
1855 /* Get account and set it into mail_operation */
1856 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1857 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1858 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1860 /* Get folder rules */
1861 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1862 if (TNY_IS_FOLDER (parent))
1863 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1865 /* Apply operation constraints */
1866 if ((gpointer) parent == (gpointer) folder ||
1867 (!TNY_IS_FOLDER_STORE (parent)) ||
1868 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1871 } else if (TNY_IS_FOLDER (parent) &&
1872 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1876 } else if (TNY_IS_FOLDER (parent) &&
1877 TNY_IS_FOLDER_STORE (folder) &&
1878 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1879 TNY_FOLDER_STORE (folder))) {
1880 /* Do not move a parent into a child */
1882 } else if (TNY_IS_FOLDER_STORE (parent) &&
1883 modest_tny_folder_has_subfolder_with_name (parent, folder_name)) {
1884 /* Check that the new folder name is not used by any
1887 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1888 /* Check that the new folder name is not used by any
1889 special local folder */
1892 /* Create the helper */
1893 helper = g_slice_new0 (XFerMsgAsyncHelper);
1894 helper->mail_op = g_object_ref (self);
1895 helper->dest_folder = NULL;
1896 helper->headers = NULL;
1897 helper->user_callback = user_callback;
1898 helper->user_data = user_data;
1900 /* Move/Copy folder */
1901 modest_mail_operation_notify_start (self);
1902 tny_folder_copy_async (folder,
1904 tny_folder_get_name (folder),
1907 transfer_folder_status_cb,
1913 /* Set status failed and set an error */
1914 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1915 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1916 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1919 /* Call the user callback if exists */
1921 user_callback (self, user_data);
1923 /* Notify the queue */
1924 modest_mail_operation_notify_end (self);
1928 modest_mail_operation_rename_folder (ModestMailOperation *self,
1932 ModestMailOperationPrivate *priv;
1933 ModestTnyFolderRules rules;
1934 XFerMsgAsyncHelper *helper;
1936 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1937 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1938 g_return_if_fail (name);
1940 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1942 /* Get account and set it into mail_operation */
1943 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1944 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1946 /* Check folder rules */
1947 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1948 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
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_FOLDER_RULES,
1953 _("FIXME: unable to rename"));
1955 /* Notify about operation end */
1956 modest_mail_operation_notify_end (self);
1957 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1958 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1959 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1960 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1961 _("FIXME: unable to rename"));
1962 /* Notify about operation end */
1963 modest_mail_operation_notify_end (self);
1965 TnyFolderStore *into;
1967 into = tny_folder_get_folder_store (folder);
1969 /* Check that the new folder name is not used by any
1970 special local folder */
1971 if (new_name_valid_if_local_account (priv, into, name)) {
1972 /* Create the helper */
1973 helper = g_slice_new0 (XFerMsgAsyncHelper);
1974 helper->mail_op = g_object_ref(self);
1975 helper->dest_folder = NULL;
1976 helper->headers = NULL;
1977 helper->user_callback = NULL;
1978 helper->user_data = NULL;
1980 /* Rename. Camel handles folder subscription/unsubscription */
1981 modest_mail_operation_notify_start (self);
1982 tny_folder_copy_async (folder, into, name, TRUE,
1984 transfer_folder_status_cb,
1987 modest_mail_operation_notify_end (self);
1989 g_object_unref (into);
1993 /* ******************************************************************* */
1994 /* ************************** MSG ACTIONS ************************* */
1995 /* ******************************************************************* */
1998 modest_mail_operation_get_msg (ModestMailOperation *self,
2000 GetMsgAsyncUserCallback user_callback,
2003 GetMsgAsyncHelper *helper = NULL;
2005 ModestMailOperationPrivate *priv;
2007 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2008 g_return_if_fail (TNY_IS_HEADER (header));
2010 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2011 folder = tny_header_get_folder (header);
2013 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2014 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2016 /* Get message from folder */
2018 /* Get account and set it into mail_operation */
2019 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2021 /* Check for cached messages */
2022 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2023 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2025 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2027 helper = g_slice_new0 (GetMsgAsyncHelper);
2028 helper->mail_op = self;
2029 helper->user_callback = user_callback;
2030 helper->user_data = user_data;
2031 helper->header = g_object_ref (header);
2033 // The callback's reference so that the mail op is not
2034 // finalized until the async operation is completed even if
2035 // the user canceled the request meanwhile.
2036 g_object_ref (G_OBJECT (helper->mail_op));
2038 modest_mail_operation_notify_start (self);
2039 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
2041 g_object_unref (G_OBJECT (folder));
2043 /* Set status failed and set an error */
2044 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2045 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2046 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2047 _("Error trying to get a message. No folder found for header"));
2049 /* Notify the queue */
2050 modest_mail_operation_notify_end (self);
2055 get_msg_cb (TnyFolder *folder,
2061 GetMsgAsyncHelper *helper = NULL;
2062 ModestMailOperation *self = NULL;
2063 ModestMailOperationPrivate *priv = NULL;
2065 helper = (GetMsgAsyncHelper *) user_data;
2066 g_return_if_fail (helper != NULL);
2067 self = helper->mail_op;
2068 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2069 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2071 /* Check errors and cancel */
2073 priv->error = g_error_copy (error);
2074 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2075 } else if (cancelled) {
2076 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2077 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2078 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2079 _("Error trying to refresh the contents of %s"),
2080 tny_folder_get_name (folder));
2082 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2085 /* If user defined callback function was defined, call it even
2086 if the operation failed*/
2087 if (helper->user_callback) {
2088 /* This is not a GDK lock because we are a Tinymail callback
2089 * which is already GDK locked by Tinymail */
2091 /* no gdk_threads_enter (), CHECKED */
2092 helper->user_callback (self, helper->header, msg, helper->user_data);
2093 /* no gdk_threads_leave (), CHECKED */
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;
2131 /* This is not a GDK lock because we are a Tinymail callback
2132 * which is already GDK locked by Tinymail */
2134 /* no gdk_threads_enter (), CHECKED */
2135 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2136 /* no gdk_threads_leave (), CHECKED */
2138 g_slice_free (ModestMailOperationState, state);
2141 /****************************************************/
2143 ModestMailOperation *mail_op;
2145 GetMsgAsyncUserCallback user_callback;
2147 GDestroyNotify notify;
2151 GetMsgAsyncUserCallback user_callback;
2155 ModestMailOperation *mail_op;
2156 } NotifyGetMsgsInfo;
2160 * Used by get_msgs_full_thread to call the user_callback for each
2161 * message that has been read
2164 notify_get_msgs_full (gpointer data)
2166 NotifyGetMsgsInfo *info;
2168 info = (NotifyGetMsgsInfo *) data;
2170 /* This is a GDK lock because we are an idle callback and
2171 * because info->user_callback can contain Gtk+ code */
2173 gdk_threads_enter (); /* CHECKED */
2174 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2175 gdk_threads_leave (); /* CHECKED */
2177 g_slice_free (NotifyGetMsgsInfo, info);
2183 * Used by get_msgs_full_thread to free al the thread resources and to
2184 * call the destroy function for the passed user_data
2187 get_msgs_full_destroyer (gpointer data)
2189 GetFullMsgsInfo *info;
2191 info = (GetFullMsgsInfo *) data;
2195 /* This is a GDK lock because we are an idle callback and
2196 * because info->notify can contain Gtk+ code */
2198 gdk_threads_enter (); /* CHECKED */
2199 info->notify (info->user_data);
2200 gdk_threads_leave (); /* CHECKED */
2204 g_object_unref (info->headers);
2205 g_slice_free (GetFullMsgsInfo, info);
2211 get_msgs_full_thread (gpointer thr_user_data)
2213 GetFullMsgsInfo *info;
2214 ModestMailOperationPrivate *priv = NULL;
2215 TnyIterator *iter = NULL;
2217 info = (GetFullMsgsInfo *) thr_user_data;
2218 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2220 iter = tny_list_create_iterator (info->headers);
2221 while (!tny_iterator_is_done (iter)) {
2225 header = TNY_HEADER (tny_iterator_get_current (iter));
2226 folder = tny_header_get_folder (header);
2228 /* Check for cached messages */
2229 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2230 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2232 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2234 /* Get message from folder */
2237 /* The callback will call it per each header */
2238 msg = tny_folder_get_msg (folder, header, &(priv->error));
2241 ModestMailOperationState *state;
2246 /* notify progress */
2247 state = modest_mail_operation_clone_state (info->mail_op);
2248 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2249 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2250 pair, (GDestroyNotify) modest_pair_free);
2252 /* The callback is the responsible for
2253 freeing the message */
2254 if (info->user_callback) {
2255 NotifyGetMsgsInfo *info_notify;
2256 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2257 info_notify->user_callback = info->user_callback;
2258 info_notify->mail_op = info->mail_op;
2259 info_notify->header = g_object_ref (header);
2260 info_notify->msg = g_object_ref (msg);
2261 info_notify->user_data = info->user_data;
2262 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2263 notify_get_msgs_full,
2266 g_object_unref (msg);
2269 /* Set status failed and set an error */
2270 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2271 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2272 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2273 "Error trying to get a message. No folder found for header");
2277 g_object_unref (header);
2279 tny_iterator_next (iter);
2282 /* Set operation status */
2283 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2284 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2286 /* Notify about operation end */
2287 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2289 /* Free thread resources. Will be called after all previous idles */
2290 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2296 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2297 TnyList *header_list,
2298 GetMsgAsyncUserCallback user_callback,
2300 GDestroyNotify notify)
2302 TnyHeader *header = NULL;
2303 TnyFolder *folder = NULL;
2305 ModestMailOperationPrivate *priv = NULL;
2306 GetFullMsgsInfo *info = NULL;
2307 gboolean size_ok = TRUE;
2309 TnyIterator *iter = NULL;
2311 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2313 /* Init mail operation */
2314 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2315 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2316 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2318 priv->total = tny_list_get_length(header_list);
2320 /* Get account and set it into mail_operation */
2321 if (tny_list_get_length (header_list) >= 1) {
2322 iter = tny_list_create_iterator (header_list);
2323 header = TNY_HEADER (tny_iterator_get_current (iter));
2325 folder = tny_header_get_folder (header);
2327 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2328 g_object_unref (folder);
2330 g_object_unref (header);
2333 if (tny_list_get_length (header_list) == 1) {
2334 g_object_unref (iter);
2339 /* Get msg size limit */
2340 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2341 MODEST_CONF_MSG_SIZE_LIMIT,
2344 g_clear_error (&(priv->error));
2345 max_size = G_MAXINT;
2347 max_size = max_size * KB;
2350 /* Check message size limits. If there is only one message
2351 always retrieve it */
2353 while (!tny_iterator_is_done (iter) && size_ok) {
2354 header = TNY_HEADER (tny_iterator_get_current (iter));
2356 if (tny_header_get_message_size (header) >= max_size)
2358 g_object_unref (header);
2361 tny_iterator_next (iter);
2363 g_object_unref (iter);
2367 /* Create the info */
2368 info = g_slice_new0 (GetFullMsgsInfo);
2369 info->mail_op = self;
2370 info->user_callback = user_callback;
2371 info->user_data = user_data;
2372 info->headers = g_object_ref (header_list);
2373 info->notify = notify;
2375 modest_mail_operation_notify_start (self);
2376 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2378 /* Set status failed and set an error */
2379 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2380 /* FIXME: the error msg is different for pop */
2381 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2382 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2383 _("emev_ni_ui_imap_msg_size_exceed_error"));
2384 /* Remove from queue and free resources */
2385 modest_mail_operation_notify_end (self);
2393 modest_mail_operation_remove_msg (ModestMailOperation *self,
2395 gboolean remove_to_trash /*ignored*/)
2398 ModestMailOperationPrivate *priv;
2400 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2401 g_return_if_fail (TNY_IS_HEADER (header));
2403 if (remove_to_trash)
2404 g_warning ("remove to trash is not implemented");
2406 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2407 folder = tny_header_get_folder (header);
2409 /* Get account and set it into mail_operation */
2410 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2411 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2412 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2414 /* remove message from folder */
2415 tny_folder_remove_msg (folder, header, &(priv->error));
2417 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2418 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2420 modest_mail_operation_notify_start (self);
2422 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2423 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* FALSE --> don't expunge *\/ */
2424 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2425 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2426 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* TRUE --> dont expunge *\/ */
2427 tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2430 /* tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /\* TRUE --> expunge *\/ */
2431 tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2437 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2439 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2442 g_object_unref (G_OBJECT (folder));
2444 /* Notify about operation end */
2445 modest_mail_operation_notify_end (self);
2449 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2451 gboolean remove_to_trash /*ignored*/)
2454 ModestMailOperationPrivate *priv;
2455 TnyIterator *iter = NULL;
2456 TnyHeader *header = NULL;
2458 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2459 g_return_if_fail (TNY_IS_LIST (headers));
2461 if (remove_to_trash)
2462 g_warning ("remove to trash is not implemented");
2464 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2466 /* Get folder from first header and sync it */
2467 iter = tny_list_create_iterator (headers);
2468 header = TNY_HEADER (tny_iterator_get_current (iter));
2469 folder = tny_header_get_folder (header);
2471 /* Get account and set it into mail_operation */
2472 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2473 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2474 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2476 /* remove message from folder */
2477 modest_mail_operation_notify_start (self);
2479 tny_folder_remove_msgs (folder, headers, &(priv->error));
2481 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2482 TNY_IS_CAMEL_POP_FOLDER (folder))
2483 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> don't expunge */
2486 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2492 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2494 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2497 g_object_unref (header);
2498 g_object_unref (iter);
2499 g_object_unref (G_OBJECT (folder));
2501 /* Notify about operation end */
2502 modest_mail_operation_notify_end (self);
2507 transfer_msgs_status_cb (GObject *obj,
2511 XFerMsgAsyncHelper *helper = NULL;
2512 ModestMailOperation *self;
2513 ModestMailOperationPrivate *priv;
2514 ModestMailOperationState *state;
2517 g_return_if_fail (status != NULL);
2518 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2520 helper = (XFerMsgAsyncHelper *) user_data;
2521 g_return_if_fail (helper != NULL);
2523 self = helper->mail_op;
2524 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2526 priv->done = status->position;
2527 priv->total = status->of_total;
2529 state = modest_mail_operation_clone_state (self);
2531 /* This is not a GDK lock because we are a Tinymail callback and
2532 * Tinymail already acquires the Gdk lock */
2534 /* no gdk_threads_enter (), CHECKED */
2536 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2538 /* no gdk_threads_leave (), CHECKED */
2540 g_slice_free (ModestMailOperationState, state);
2545 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2547 XFerMsgAsyncHelper *helper;
2548 ModestMailOperation *self;
2549 ModestMailOperationPrivate *priv;
2550 TnyIterator *iter = NULL;
2551 TnyHeader *header = NULL;
2553 helper = (XFerMsgAsyncHelper *) user_data;
2554 self = helper->mail_op;
2556 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2559 priv->error = g_error_copy (err);
2561 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2562 } else if (cancelled) {
2563 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2564 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2565 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2566 _("Error trying to refresh the contents of %s"),
2567 tny_folder_get_name (folder));
2570 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2572 /* Update folder counts */
2573 tny_folder_poke_status (folder);
2574 tny_folder_poke_status (helper->dest_folder);
2578 /* Mark headers as deleted and seen */
2579 if ((helper->delete) &&
2580 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2581 iter = tny_list_create_iterator (helper->headers);
2582 while (!tny_iterator_is_done (iter)) {
2583 header = TNY_HEADER (tny_iterator_get_current (iter));
2584 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2585 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2586 g_object_unref (header);
2588 tny_iterator_next (iter);
2594 /* Notify about operation end */
2595 modest_mail_operation_notify_end (self);
2597 /* If user defined callback function was defined, call it */
2598 if (helper->user_callback) {
2599 /* This is not a GDK lock because we are a Tinymail callback and
2600 * Tinymail already acquires the Gdk lock */
2602 /* no gdk_threads_enter (), CHECKED */
2603 helper->user_callback (self, helper->user_data);
2604 /* no gdk_threads_leave (), CHECKED */
2608 if (helper->headers)
2609 g_object_unref (helper->headers);
2610 if (helper->dest_folder)
2611 g_object_unref (helper->dest_folder);
2612 if (helper->mail_op)
2613 g_object_unref (helper->mail_op);
2615 g_object_unref (folder);
2617 g_object_unref (iter);
2618 g_slice_free (XFerMsgAsyncHelper, helper);
2622 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2625 gboolean delete_original,
2626 XferAsyncUserCallback user_callback,
2629 ModestMailOperationPrivate *priv = NULL;
2630 TnyIterator *iter = NULL;
2631 TnyFolder *src_folder = NULL;
2632 XFerMsgAsyncHelper *helper = NULL;
2633 TnyHeader *header = NULL;
2634 ModestTnyFolderRules rules = 0;
2636 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2637 g_return_if_fail (TNY_IS_LIST (headers));
2638 g_return_if_fail (TNY_IS_FOLDER (folder));
2640 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2643 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2644 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2646 /* Apply folder rules */
2647 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2648 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2649 /* Set status failed and set an error */
2650 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2651 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2652 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2653 _CS("ckct_ib_unable_to_paste_here"));
2654 /* Notify the queue */
2655 modest_mail_operation_notify_end (self);
2659 /* Get source folder */
2660 iter = tny_list_create_iterator (headers);
2661 header = TNY_HEADER (tny_iterator_get_current (iter));
2663 src_folder = tny_header_get_folder (header);
2664 g_object_unref (header);
2667 g_object_unref (iter);
2669 /* Check folder source and destination */
2670 if (src_folder == folder) {
2671 /* Set status failed and set an error */
2672 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2673 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2674 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2675 _("mcen_ib_unable_to_copy_samefolder"));
2677 /* Notify the queue */
2678 modest_mail_operation_notify_end (self);
2681 g_object_unref (src_folder);
2685 /* Create the helper */
2686 helper = g_slice_new0 (XFerMsgAsyncHelper);
2687 helper->mail_op = g_object_ref(self);
2688 helper->dest_folder = g_object_ref(folder);
2689 helper->headers = g_object_ref(headers);
2690 helper->user_callback = user_callback;
2691 helper->user_data = user_data;
2692 helper->delete = delete_original;
2694 /* Get account and set it into mail_operation */
2695 priv->account = modest_tny_folder_get_account (src_folder);
2697 /* Transfer messages */
2698 modest_mail_operation_notify_start (self);
2699 tny_folder_transfer_msgs_async (src_folder,
2704 transfer_msgs_status_cb,
2710 on_refresh_folder (TnyFolder *folder,
2715 RefreshAsyncHelper *helper = NULL;
2716 ModestMailOperation *self = NULL;
2717 ModestMailOperationPrivate *priv = NULL;
2719 helper = (RefreshAsyncHelper *) user_data;
2720 self = helper->mail_op;
2721 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2723 g_return_if_fail(priv!=NULL);
2726 priv->error = g_error_copy (error);
2727 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2732 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2733 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2734 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2735 _("Error trying to refresh the contents of %s"),
2736 tny_folder_get_name (folder));
2740 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2743 /* Call user defined callback, if it exists */
2744 if (helper->user_callback) {
2746 /* This is not a GDK lock because we are a Tinymail callback and
2747 * Tinymail already acquires the Gdk lock */
2748 helper->user_callback (self, folder, helper->user_data);
2752 g_slice_free (RefreshAsyncHelper, helper);
2754 /* Notify about operation end */
2755 modest_mail_operation_notify_end (self);
2756 g_object_unref(self);
2760 on_refresh_folder_status_update (GObject *obj,
2764 RefreshAsyncHelper *helper = NULL;
2765 ModestMailOperation *self = NULL;
2766 ModestMailOperationPrivate *priv = NULL;
2767 ModestMailOperationState *state;
2769 g_return_if_fail (user_data != NULL);
2770 g_return_if_fail (status != NULL);
2771 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2773 helper = (RefreshAsyncHelper *) user_data;
2774 self = helper->mail_op;
2775 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2777 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2779 priv->done = status->position;
2780 priv->total = status->of_total;
2782 state = modest_mail_operation_clone_state (self);
2784 /* This is not a GDK lock because we are a Tinymail callback and
2785 * Tinymail already acquires the Gdk lock */
2786 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2788 g_slice_free (ModestMailOperationState, state);
2792 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2794 RefreshAsyncUserCallback user_callback,
2797 ModestMailOperationPrivate *priv = NULL;
2798 RefreshAsyncHelper *helper = NULL;
2800 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2802 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2804 /* Get account and set it into mail_operation */
2805 priv->account = modest_tny_folder_get_account (folder);
2806 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2808 /* Create the helper */
2809 helper = g_slice_new0 (RefreshAsyncHelper);
2810 helper->mail_op = g_object_ref(self);
2811 helper->user_callback = user_callback;
2812 helper->user_data = user_data;
2814 /* Refresh the folder. TODO: tinymail could issue a status
2815 updates before the callback call then this could happen. We
2816 must review the design */
2817 modest_mail_operation_notify_start (self);
2818 tny_folder_refresh_async (folder,
2820 on_refresh_folder_status_update,
2826 modest_mail_operation_notify_start (ModestMailOperation *self)
2828 ModestMailOperationPrivate *priv = NULL;
2830 g_return_if_fail (self);
2832 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2834 /* Ensure that all the fields are filled correctly */
2835 g_return_if_fail (priv->account != NULL);
2836 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
2838 /* Notify the observers about the mail operation. We do not
2839 wrapp this emission because we assume that this function is
2840 always called from within the main lock */
2841 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
2846 * It's used by the mail operation queue to notify the observers
2847 * attached to that signal that the operation finished. We need to use
2848 * that because tinymail does not give us the progress of a given
2849 * operation when it finishes (it directly calls the operation
2853 modest_mail_operation_notify_end (ModestMailOperation *self)
2855 ModestMailOperationPrivate *priv = NULL;
2857 g_return_if_fail (self);
2859 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2861 /* Notify the observers about the mail operation end. We do
2862 not wrapp this emission because we assume that this
2863 function is always called from within the main lock */
2864 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
2868 modest_mail_operation_get_account (ModestMailOperation *self)
2870 ModestMailOperationPrivate *priv = NULL;
2872 g_return_val_if_fail (self, NULL);
2874 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2876 return (priv->account) ? g_object_ref (priv->account) : NULL;