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_end (ModestMailOperation *self);
86 enum _ModestMailOperationSignals
88 PROGRESS_CHANGED_SIGNAL,
93 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
94 struct _ModestMailOperationPrivate {
101 ErrorCheckingUserCallback error_checking;
102 gpointer error_checking_user_data;
103 ModestMailOperationStatus status;
104 ModestMailOperationTypeOperation op_type;
107 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
108 MODEST_TYPE_MAIL_OPERATION, \
109 ModestMailOperationPrivate))
111 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
112 priv->status = new_status;\
115 typedef struct _GetMsgAsyncHelper {
116 ModestMailOperation *mail_op;
118 GetMsgAsyncUserCallback user_callback;
122 typedef struct _RefreshAsyncHelper {
123 ModestMailOperation *mail_op;
124 RefreshAsyncUserCallback user_callback;
126 } RefreshAsyncHelper;
128 typedef struct _XFerMsgAsyncHelper
130 ModestMailOperation *mail_op;
132 TnyFolder *dest_folder;
133 XferAsyncUserCallback user_callback;
136 } XFerMsgAsyncHelper;
138 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
142 static void modest_mail_operation_create_msg (ModestMailOperation *self,
143 const gchar *from, const gchar *to,
144 const gchar *cc, const gchar *bcc,
145 const gchar *subject, const gchar *plain_body,
146 const gchar *html_body, const GList *attachments_list,
147 const GList *images_list,
148 TnyHeaderFlags priority_flags,
149 ModestMailOperationCreateMsgCallback callback,
152 static gboolean idle_notify_queue (gpointer data);
155 ModestMailOperation *mail_op;
163 GList *attachments_list;
165 TnyHeaderFlags priority_flags;
166 ModestMailOperationCreateMsgCallback callback;
172 ModestMailOperation *mail_op;
174 ModestMailOperationCreateMsgCallback callback;
179 static GObjectClass *parent_class = NULL;
181 static guint signals[NUM_SIGNALS] = {0};
184 modest_mail_operation_get_type (void)
186 static GType my_type = 0;
188 static const GTypeInfo my_info = {
189 sizeof(ModestMailOperationClass),
190 NULL, /* base init */
191 NULL, /* base finalize */
192 (GClassInitFunc) modest_mail_operation_class_init,
193 NULL, /* class finalize */
194 NULL, /* class data */
195 sizeof(ModestMailOperation),
197 (GInstanceInitFunc) modest_mail_operation_init,
200 my_type = g_type_register_static (G_TYPE_OBJECT,
201 "ModestMailOperation",
208 modest_mail_operation_class_init (ModestMailOperationClass *klass)
210 GObjectClass *gobject_class;
211 gobject_class = (GObjectClass*) klass;
213 parent_class = g_type_class_peek_parent (klass);
214 gobject_class->finalize = modest_mail_operation_finalize;
216 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
219 * ModestMailOperation::progress-changed
220 * @self: the #MailOperation that emits the signal
221 * @user_data: user data set when the signal handler was connected
223 * Emitted when the progress of a mail operation changes
225 signals[PROGRESS_CHANGED_SIGNAL] =
226 g_signal_new ("progress-changed",
227 G_TYPE_FROM_CLASS (gobject_class),
229 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
231 g_cclosure_marshal_VOID__POINTER,
232 G_TYPE_NONE, 1, G_TYPE_POINTER);
237 modest_mail_operation_init (ModestMailOperation *obj)
239 ModestMailOperationPrivate *priv;
241 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
243 priv->account = NULL;
244 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
245 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
250 priv->error_checking = NULL;
251 priv->error_checking_user_data = NULL;
255 modest_mail_operation_finalize (GObject *obj)
257 ModestMailOperationPrivate *priv;
259 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
264 g_error_free (priv->error);
268 g_object_unref (priv->source);
272 g_object_unref (priv->account);
273 priv->account = NULL;
277 G_OBJECT_CLASS(parent_class)->finalize (obj);
281 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
284 ModestMailOperation *obj;
285 ModestMailOperationPrivate *priv;
287 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
288 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
290 priv->op_type = op_type;
292 priv->source = g_object_ref(source);
298 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
300 ErrorCheckingUserCallback error_handler,
303 ModestMailOperation *obj;
304 ModestMailOperationPrivate *priv;
306 obj = modest_mail_operation_new (op_type, source);
307 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
309 g_return_val_if_fail (error_handler != NULL, obj);
310 priv->error_checking = error_handler;
311 priv->error_checking_user_data = user_data;
317 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
319 ModestMailOperationPrivate *priv;
321 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
322 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
324 if (priv->error_checking != NULL)
325 priv->error_checking (self, priv->error_checking_user_data);
329 ModestMailOperationTypeOperation
330 modest_mail_operation_get_type_operation (ModestMailOperation *self)
332 ModestMailOperationPrivate *priv;
334 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
336 return priv->op_type;
340 modest_mail_operation_is_mine (ModestMailOperation *self,
343 ModestMailOperationPrivate *priv;
345 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
346 if (priv->source == NULL) return FALSE;
348 return priv->source == me;
352 modest_mail_operation_get_source (ModestMailOperation *self)
354 ModestMailOperationPrivate *priv;
356 g_return_val_if_fail (self, NULL);
358 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
360 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
364 return (priv->source) ? g_object_ref (priv->source) : NULL;
367 ModestMailOperationStatus
368 modest_mail_operation_get_status (ModestMailOperation *self)
370 ModestMailOperationPrivate *priv;
372 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
373 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
374 MODEST_MAIL_OPERATION_STATUS_INVALID);
376 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
378 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
379 return MODEST_MAIL_OPERATION_STATUS_INVALID;
386 modest_mail_operation_get_error (ModestMailOperation *self)
388 ModestMailOperationPrivate *priv;
390 g_return_val_if_fail (self, NULL);
391 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
393 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
396 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
404 modest_mail_operation_cancel (ModestMailOperation *self)
406 ModestMailOperationPrivate *priv;
407 gboolean canceled = FALSE;
409 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
411 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
413 /* Note that if we call cancel with an already canceled mail
414 operation the progress changed signal won't be emitted */
415 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
419 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
421 /* Cancel the mail operation. We need to wrap it between this
422 start/stop operations to allow following calls to the
424 g_return_val_if_fail (priv->account, FALSE);
425 tny_account_cancel (priv->account);
431 modest_mail_operation_get_task_done (ModestMailOperation *self)
433 ModestMailOperationPrivate *priv;
435 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
437 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
442 modest_mail_operation_get_task_total (ModestMailOperation *self)
444 ModestMailOperationPrivate *priv;
446 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
448 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
453 modest_mail_operation_is_finished (ModestMailOperation *self)
455 ModestMailOperationPrivate *priv;
456 gboolean retval = FALSE;
458 if (!MODEST_IS_MAIL_OPERATION (self)) {
459 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
463 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
465 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
466 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
467 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
468 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
478 modest_mail_operation_get_id (ModestMailOperation *self)
480 ModestMailOperationPrivate *priv;
482 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
484 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
489 modest_mail_operation_set_id (ModestMailOperation *self,
492 ModestMailOperationPrivate *priv;
494 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
496 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
501 * Creates an image of the current state of a mail operation, the
502 * caller must free it
504 static ModestMailOperationState *
505 modest_mail_operation_clone_state (ModestMailOperation *self)
507 ModestMailOperationState *state;
508 ModestMailOperationPrivate *priv;
510 /* FIXME: this should be fixed properly
512 * in some cases, priv was NULL, so checking here to
515 g_return_val_if_fail (self, NULL);
516 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
517 g_return_val_if_fail (priv, NULL);
522 state = g_slice_new (ModestMailOperationState);
524 state->status = priv->status;
525 state->op_type = priv->op_type;
526 state->done = priv->done;
527 state->total = priv->total;
528 state->finished = modest_mail_operation_is_finished (self);
529 state->bytes_done = 0;
530 state->bytes_total = 0;
535 /* ******************************************************************* */
536 /* ************************** SEND ACTIONS ************************* */
537 /* ******************************************************************* */
540 modest_mail_operation_send_mail (ModestMailOperation *self,
541 TnyTransportAccount *transport_account,
544 TnySendQueue *send_queue = NULL;
545 ModestMailOperationPrivate *priv;
547 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
548 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
549 g_return_if_fail (TNY_IS_MSG (msg));
551 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
553 /* Get account and set it into mail_operation */
554 priv->account = g_object_ref (transport_account);
558 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
559 if (!TNY_IS_SEND_QUEUE(send_queue)) {
560 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
561 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
562 "modest: could not find send queue for account\n");
563 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
566 /* TODO: connect to the msg-sent in order to know when
567 the mail operation is finished */
569 /* tny_send_queue_add (send_queue, msg, &(priv->error)); */
570 modest_tny_send_queue_add (MODEST_TNY_SEND_QUEUE(send_queue),
574 /* TODO: we're setting always success, do the check in
576 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
579 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)
580 modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
582 /* TODO: do this in the handler of the "msg-sent"
583 signal.Notify about operation end */
584 modest_mail_operation_notify_end (self);
588 idle_create_msg_cb (gpointer idle_data)
590 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
592 /* This is a GDK lock because we are an idle callback and
593 * info->callback can contain Gtk+ code */
595 gdk_threads_enter (); /* CHECKED */
596 info->callback (info->mail_op, info->msg, info->userdata);
598 g_object_unref (info->mail_op);
600 g_object_unref (info->msg);
601 g_slice_free (CreateMsgIdleInfo, info);
602 gdk_threads_leave (); /* CHECKED */
608 create_msg_thread (gpointer thread_data)
610 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
611 TnyMsg *new_msg = NULL;
612 ModestMailOperationPrivate *priv;
614 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
615 if (info->html_body == NULL) {
616 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
617 info->bcc, info->subject, info->plain_body,
618 info->attachments_list);
620 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
621 info->bcc, info->subject, info->html_body,
622 info->plain_body, info->attachments_list,
628 TnyHeaderFlags flags = 0;
630 /* Set priority flags in message */
631 header = tny_msg_get_header (new_msg);
632 if (info->priority_flags != 0)
633 flags |= info->priority_flags;
635 /* Set attachment flags in message */
636 if (info->attachments_list != NULL)
637 flags |= TNY_HEADER_FLAG_ATTACHMENTS;
639 tny_header_set_flags (header, flags);
640 g_object_unref (G_OBJECT(header));
642 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
643 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
644 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
645 "modest: failed to create a new msg\n");
653 g_free (info->plain_body);
654 g_free (info->html_body);
655 g_free (info->subject);
656 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
657 g_list_free (info->attachments_list);
658 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
659 g_list_free (info->images_list);
661 if (info->callback) {
662 CreateMsgIdleInfo *idle_info;
663 idle_info = g_slice_new0 (CreateMsgIdleInfo);
664 idle_info->mail_op = info->mail_op;
665 g_object_ref (info->mail_op);
666 idle_info->msg = new_msg;
668 g_object_ref (new_msg);
669 idle_info->callback = info->callback;
670 idle_info->userdata = info->userdata;
671 g_idle_add (idle_create_msg_cb, idle_info);
673 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
676 g_object_unref (info->mail_op);
677 g_slice_free (CreateMsgInfo, info);
682 modest_mail_operation_create_msg (ModestMailOperation *self,
683 const gchar *from, const gchar *to,
684 const gchar *cc, const gchar *bcc,
685 const gchar *subject, const gchar *plain_body,
686 const gchar *html_body,
687 const GList *attachments_list,
688 const GList *images_list,
689 TnyHeaderFlags priority_flags,
690 ModestMailOperationCreateMsgCallback callback,
693 CreateMsgInfo *info = NULL;
695 info = g_slice_new0 (CreateMsgInfo);
696 info->mail_op = self;
699 info->from = g_strdup (from);
700 info->to = g_strdup (to);
701 info->cc = g_strdup (cc);
702 info->bcc = g_strdup (bcc);
703 info->subject = g_strdup (subject);
704 info->plain_body = g_strdup (plain_body);
705 info->html_body = g_strdup (html_body);
706 info->attachments_list = g_list_copy ((GList *) attachments_list);
707 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
708 info->images_list = g_list_copy ((GList *) images_list);
709 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
710 info->priority_flags = priority_flags;
712 info->callback = callback;
713 info->userdata = userdata;
715 g_thread_create (create_msg_thread, info, FALSE, NULL);
720 TnyTransportAccount *transport_account;
725 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
729 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
730 TnyFolder *draft_folder = NULL;
731 TnyFolder *outbox_folder = NULL;
739 /* Call mail operation */
740 modest_mail_operation_send_mail (self, info->transport_account, msg);
742 /* Remove old mail from its source folder */
743 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
744 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_OUTBOX);
745 if (info->draft_msg != NULL) {
746 TnyFolder *folder = NULL;
747 TnyFolder *src_folder = NULL;
748 TnyFolderType folder_type;
749 folder = tny_msg_get_folder (info->draft_msg);
750 if (folder == NULL) goto end;
751 folder_type = modest_tny_folder_guess_folder_type (folder);
752 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
753 src_folder = outbox_folder;
755 src_folder = draft_folder;
757 /* Note: This can fail (with a warning) if the message is not really already in a folder,
758 * because this function requires it to have a UID. */
759 header = tny_msg_get_header (info->draft_msg);
760 tny_folder_remove_msg (src_folder, header, NULL);
762 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
763 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
765 g_object_unref (header);
766 g_object_unref (folder);
773 g_object_unref (info->draft_msg);
775 g_object_unref (draft_folder);
777 g_object_unref (outbox_folder);
778 if (info->transport_account)
779 g_object_unref (info->transport_account);
780 g_slice_free (SendNewMailInfo, info);
781 modest_mail_operation_notify_end (self);
785 modest_mail_operation_send_new_mail (ModestMailOperation *self,
786 TnyTransportAccount *transport_account,
788 const gchar *from, const gchar *to,
789 const gchar *cc, const gchar *bcc,
790 const gchar *subject, const gchar *plain_body,
791 const gchar *html_body,
792 const GList *attachments_list,
793 const GList *images_list,
794 TnyHeaderFlags priority_flags)
796 ModestMailOperationPrivate *priv = NULL;
797 SendNewMailInfo *info;
799 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
800 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
802 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
804 /* Check parametters */
806 /* Set status failed and set an error */
807 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
808 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
809 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
810 _("Error trying to send a mail. You need to set at least one recipient"));
813 info = g_slice_new0 (SendNewMailInfo);
814 info->transport_account = transport_account;
815 if (transport_account)
816 g_object_ref (transport_account);
817 info->draft_msg = draft_msg;
819 g_object_ref (draft_msg);
820 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
821 attachments_list, images_list, priority_flags,
822 modest_mail_operation_send_new_mail_cb, info);
828 TnyTransportAccount *transport_account;
830 ModestMsgEditWindow *edit_window;
834 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
838 TnyFolder *src_folder = NULL;
839 TnyFolder *drafts = NULL;
840 TnyHeader *header = NULL;
841 ModestMailOperationPrivate *priv = NULL;
842 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
844 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
846 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
847 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
848 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
849 "modest: failed to create a new msg\n");
853 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
854 TNY_FOLDER_TYPE_DRAFTS);
856 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
857 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
858 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
859 "modest: failed to create a new msg\n");
864 tny_folder_add_msg (drafts, msg, &(priv->error));
866 if ((!priv->error) && (info->draft_msg != NULL)) {
867 header = tny_msg_get_header (info->draft_msg);
868 src_folder = tny_header_get_folder (header);
870 /* Remove the old draft */
871 tny_folder_remove_msg (src_folder, header, NULL);
873 /* Synchronize to expunge and to update the msg counts */
874 tny_folder_sync_async (drafts, TRUE, NULL, NULL, NULL);
875 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
877 g_object_unref (header);
881 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
883 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
885 if (info->edit_window)
886 modest_msg_edit_window_set_draft (info->edit_window, msg);
891 g_object_unref (G_OBJECT(drafts));
893 g_object_unref (G_OBJECT(src_folder));
894 if (info->edit_window)
895 g_object_unref (G_OBJECT(info->edit_window));
897 g_object_unref (G_OBJECT (info->draft_msg));
898 if (info->transport_account)
899 g_object_unref (G_OBJECT(info->transport_account));
900 g_slice_free (SaveToDraftsInfo, info);
902 modest_mail_operation_notify_end (self);
906 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
907 TnyTransportAccount *transport_account,
909 ModestMsgEditWindow *edit_window,
910 const gchar *from, const gchar *to,
911 const gchar *cc, const gchar *bcc,
912 const gchar *subject, const gchar *plain_body,
913 const gchar *html_body,
914 const GList *attachments_list,
915 const GList *images_list,
916 TnyHeaderFlags priority_flags)
918 ModestMailOperationPrivate *priv = NULL;
919 SaveToDraftsInfo *info = NULL;
921 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
922 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
924 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
926 /* Get account and set it into mail_operation */
927 priv->account = g_object_ref (transport_account);
929 info = g_slice_new0 (SaveToDraftsInfo);
930 info->transport_account = g_object_ref (transport_account);
931 info->draft_msg = draft_msg;
933 g_object_ref (draft_msg);
934 info->edit_window = edit_window;
936 g_object_ref (edit_window);
938 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
939 attachments_list, images_list, priority_flags,
940 modest_mail_operation_save_to_drafts_cb, info);
946 ModestMailOperation *mail_op;
947 TnyStoreAccount *account;
948 TnyTransportAccount *transport_account;
951 gchar *retrieve_type;
953 UpdateAccountCallback callback;
955 TnyList *new_headers;
960 ModestMailOperation *mail_op;
961 TnyMimePart *mime_part;
963 GetMimePartSizeCallback callback;
965 } GetMimePartSizeInfo;
967 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
968 /* We use this folder observer to track the headers that have been
969 * added to a folder */
972 TnyList *new_headers;
973 } InternalFolderObserver;
977 } InternalFolderObserverClass;
979 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
981 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
982 internal_folder_observer,
984 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
988 foreach_add_item (gpointer header, gpointer user_data)
990 tny_list_prepend (TNY_LIST (user_data),
991 g_object_ref (G_OBJECT (header)));
994 /* This is the method that looks for new messages in a folder */
996 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
998 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1000 TnyFolderChangeChanged changed;
1002 changed = tny_folder_change_get_changed (change);
1004 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1007 /* Get added headers */
1008 list = tny_simple_list_new ();
1009 tny_folder_change_get_added_headers (change, list);
1011 /* Add them to the folder observer */
1012 tny_list_foreach (list, foreach_add_item,
1013 derived->new_headers);
1015 g_object_unref (G_OBJECT (list));
1020 internal_folder_observer_init (InternalFolderObserver *self)
1022 self->new_headers = tny_simple_list_new ();
1025 internal_folder_observer_finalize (GObject *object)
1027 InternalFolderObserver *self;
1029 self = (InternalFolderObserver *) object;
1030 g_object_unref (self->new_headers);
1032 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1035 tny_folder_observer_init (TnyFolderObserverIface *iface)
1037 iface->update_func = internal_folder_observer_update;
1040 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1042 GObjectClass *object_class;
1044 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1045 object_class = (GObjectClass*) klass;
1046 object_class->finalize = internal_folder_observer_finalize;
1052 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
1055 TnyList *folders = tny_simple_list_new ();
1057 tny_folder_store_get_folders (store, folders, query, NULL);
1058 iter = tny_list_create_iterator (folders);
1060 while (!tny_iterator_is_done (iter)) {
1062 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1064 tny_list_prepend (all_folders, G_OBJECT (folder));
1065 recurse_folders (folder, query, all_folders);
1066 g_object_unref (G_OBJECT (folder));
1069 tny_iterator_next (iter);
1071 g_object_unref (G_OBJECT (iter));
1072 g_object_unref (G_OBJECT (folders));
1076 * Issues the "progress-changed" signal. The timer won't be removed,
1077 * so you must call g_source_remove to stop the signal emission
1080 idle_notify_progress (gpointer data)
1082 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1083 ModestMailOperationState *state;
1085 state = modest_mail_operation_clone_state (mail_op);
1087 /* This is a GDK lock because we are an idle callback and
1088 * the handlers of this signal can contain Gtk+ code */
1090 gdk_threads_enter (); /* CHECKED */
1091 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1092 gdk_threads_leave (); /* CHECKED */
1094 g_slice_free (ModestMailOperationState, state);
1100 * Issues the "progress-changed" signal and removes the timer. It uses
1101 * a lock to ensure that the progress information of the mail
1102 * operation is not modified while there are notifications pending
1105 idle_notify_progress_once (gpointer data)
1109 pair = (ModestPair *) data;
1111 /* This is a GDK lock because we are an idle callback and
1112 * the handlers of this signal can contain Gtk+ code */
1114 gdk_threads_enter (); /* CHECKED */
1115 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1116 gdk_threads_leave (); /* CHECKED */
1118 /* Free the state and the reference to the mail operation */
1119 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1120 g_object_unref (pair->first);
1126 * Used to notify the queue from the main
1127 * loop. We call it inside an idle call to achieve that
1130 idle_notify_queue (gpointer data)
1132 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1134 /* Do not need to block, the notify end will do it for us */
1135 modest_mail_operation_notify_end (mail_op);
1136 g_object_unref (mail_op);
1142 compare_headers_by_date (gconstpointer a,
1145 TnyHeader **header1, **header2;
1146 time_t sent1, sent2;
1148 header1 = (TnyHeader **) a;
1149 header2 = (TnyHeader **) b;
1151 sent1 = tny_header_get_date_sent (*header1);
1152 sent2 = tny_header_get_date_sent (*header2);
1154 /* We want the most recent ones (greater time_t) at the
1163 set_last_updated_idle (gpointer data)
1166 /* This is a GDK lock because we are an idle callback and
1167 * modest_account_mgr_set_last_updated can issue Gtk+ code */
1169 gdk_threads_enter (); /* CHECKED - please recheck */
1171 /* It does not matter if the time is not exactly the same than
1172 the time when this idle was called, it's just an
1173 approximation and it won't be very different */
1175 modest_account_mgr_set_last_updated (modest_runtime_get_account_mgr (),
1179 gdk_threads_leave (); /* CHECKED - please recheck */
1185 idle_update_account_cb (gpointer data)
1187 UpdateAccountInfo *idle_info;
1189 idle_info = (UpdateAccountInfo *) data;
1191 /* This is a GDK lock because we are an idle callback and
1192 * idle_info->callback can contain Gtk+ code */
1194 gdk_threads_enter (); /* CHECKED */
1195 idle_info->callback (idle_info->mail_op,
1196 idle_info->new_headers,
1197 idle_info->user_data);
1198 gdk_threads_leave (); /* CHECKED */
1201 g_object_unref (idle_info->mail_op);
1202 if (idle_info->new_headers)
1203 g_object_unref (idle_info->new_headers);
1210 get_all_folders_from_account (TnyStoreAccount *account,
1213 TnyList *all_folders = NULL;
1214 TnyIterator *iter = NULL;
1215 TnyFolderStoreQuery *query = NULL;
1217 all_folders = tny_simple_list_new ();
1218 query = tny_folder_store_query_new ();
1219 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1220 tny_folder_store_get_folders (TNY_FOLDER_STORE (account),
1227 g_object_unref (all_folders);
1231 iter = tny_list_create_iterator (all_folders);
1232 while (!tny_iterator_is_done (iter)) {
1233 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1235 recurse_folders (folder, query, all_folders);
1236 g_object_unref (folder);
1238 tny_iterator_next (iter);
1240 g_object_unref (G_OBJECT (iter));
1247 update_account_thread (gpointer thr_user_data)
1249 static gboolean first_time = TRUE;
1250 UpdateAccountInfo *info = NULL;
1251 TnyList *all_folders = NULL, *new_headers = NULL;
1252 GPtrArray *new_headers_array = NULL;
1253 TnyIterator *iter = NULL;
1254 ModestMailOperationPrivate *priv = NULL;
1255 ModestTnySendQueue *send_queue = NULL;
1256 gint i = 0, timeout = 0;
1258 info = (UpdateAccountInfo *) thr_user_data;
1259 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1261 /* Get account and set it into mail_operation */
1262 priv->account = g_object_ref (info->account);
1264 /* Get all the folders. We can do it synchronously because
1265 we're already running in a different thread than the UI */
1266 all_folders = get_all_folders_from_account (info->account, &(priv->error));
1268 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1272 /* Update status and notify. We need to call the notification
1273 with a source function in order to call it from the main
1274 loop. We need that in order not to get into trouble with
1275 Gtk+. We use a timeout in order to provide more status
1276 information, because the sync tinymail call does not
1277 provide it for the moment */
1278 timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1280 new_headers_array = g_ptr_array_new ();
1281 iter = tny_list_create_iterator (all_folders);
1283 while (!tny_iterator_is_done (iter) && !priv->error &&
1284 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1286 TnyFolderType folder_type;
1287 TnyFolder *folder = NULL;
1289 folder = TNY_FOLDER (tny_iterator_get_current (iter));
1290 folder_type = tny_folder_get_folder_type (folder);
1292 /* Refresh it only if it's the INBOX */
1293 if (folder_type == TNY_FOLDER_TYPE_INBOX) {
1294 InternalFolderObserver *observer = NULL;
1295 TnyIterator *new_headers_iter = NULL;
1297 /* Refresh the folder. Our observer receives
1298 * the new emails during folder refreshes, so
1299 * we can use observer->new_headers
1301 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1302 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1304 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1306 new_headers_iter = tny_list_create_iterator (observer->new_headers);
1307 while (!tny_iterator_is_done (new_headers_iter)) {
1308 TnyHeader *header = NULL;
1310 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1311 /* Apply per-message size limits */
1312 if (tny_header_get_message_size (header) < info->max_size)
1313 g_ptr_array_add (new_headers_array, g_object_ref (header));
1315 g_object_unref (header);
1316 tny_iterator_next (new_headers_iter);
1318 g_object_unref (new_headers_iter);
1320 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1321 g_object_unref (observer);
1323 /* We no not need to do it the first time,
1324 because it's automatically done by the tree
1326 if (G_LIKELY (!first_time))
1327 tny_folder_poke_status (folder);
1329 g_object_unref (folder);
1331 tny_iterator_next (iter);
1333 g_object_unref (G_OBJECT (iter));
1334 g_source_remove (timeout);
1336 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1337 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1338 new_headers_array->len > 0) {
1342 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1344 /* TODO: Ask the user, instead of just failing,
1345 * showing mail_nc_msg_count_limit_exceeded, with 'Get
1346 * all' and 'Newest only' buttons. */
1347 if (new_headers_array->len > info->retrieve_limit) {
1351 /* Should be get only the headers or the message as well? */
1352 if (g_ascii_strcasecmp (info->retrieve_type,
1353 MODEST_ACCOUNT_RETRIEVE_VALUE_HEADERS_ONLY) != 0) {
1355 priv->total = MIN (new_headers_array->len, info->retrieve_limit);
1356 while (msg_num < priv->total) {
1358 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1359 TnyFolder *folder = tny_header_get_folder (header);
1360 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1361 ModestMailOperationState *state;
1365 /* We can not just use the mail operation because the
1366 values of done and total could change before the
1368 state = modest_mail_operation_clone_state (info->mail_op);
1369 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1370 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1371 pair, (GDestroyNotify) modest_pair_free);
1373 g_object_unref (msg);
1374 g_object_unref (folder);
1381 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1384 /* Copy the headers to a list and free the array */
1385 new_headers = tny_simple_list_new ();
1386 for (i=0; i < new_headers_array->len; i++) {
1387 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1388 tny_list_append (new_headers, G_OBJECT (header));
1390 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1391 g_ptr_array_free (new_headers_array, FALSE);
1394 /* Perform send (if operation was not cancelled) */
1397 if (priv->account != NULL)
1398 g_object_unref (priv->account);
1399 priv->account = g_object_ref (info->transport_account);
1401 send_queue = modest_runtime_get_send_queue (info->transport_account);
1403 modest_tny_send_queue_try_to_send (send_queue);
1405 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1406 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1407 "cannot create a send queue for %s\n",
1408 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1409 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1412 /* Check if the operation was a success */
1414 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1416 /* Update the last updated key */
1417 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1418 set_last_updated_idle,
1419 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1420 (GDestroyNotify) g_free);
1425 if (info->callback) {
1426 UpdateAccountInfo *idle_info;
1428 /* This thread is not in the main lock */
1429 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1430 idle_info->mail_op = g_object_ref (info->mail_op);
1431 idle_info->new_headers = (new_headers) ? g_object_ref (new_headers) : NULL;
1432 idle_info->callback = info->callback;
1433 idle_info->user_data = info->user_data;
1434 g_idle_add (idle_update_account_cb, idle_info);
1437 /* Notify about operation end. Note that the info could be
1438 freed before this idle happens, but the mail operation will
1440 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1444 g_object_unref (new_headers);
1446 g_object_unref (all_folders);
1447 g_object_unref (info->account);
1448 g_object_unref (info->transport_account);
1449 g_free (info->retrieve_type);
1450 g_slice_free (UpdateAccountInfo, info);
1458 modest_mail_operation_update_account (ModestMailOperation *self,
1459 const gchar *account_name,
1460 UpdateAccountCallback callback,
1463 GThread *thread = NULL;
1464 UpdateAccountInfo *info = NULL;
1465 ModestMailOperationPrivate *priv = NULL;
1466 ModestAccountMgr *mgr = NULL;
1467 TnyStoreAccount *store_account = NULL;
1468 TnyTransportAccount *transport_account = NULL;
1470 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1471 g_return_val_if_fail (account_name, FALSE);
1473 /* Init mail operation. Set total and done to 0, and do not
1474 update them, this way the progress objects will know that
1475 we have no clue about the number of the objects */
1476 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1479 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1481 /* Get the store account */
1482 store_account = (TnyStoreAccount *)
1483 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1485 TNY_ACCOUNT_TYPE_STORE);
1487 if (!store_account) {
1488 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1489 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1490 "cannot get tny store account for %s\n", account_name);
1495 /* Get the transport account, we can not do it in the thread
1496 due to some problems with dbus */
1497 transport_account = (TnyTransportAccount *)
1498 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1500 if (!transport_account) {
1501 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1502 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1503 "cannot get tny transport account for %s\n", account_name);
1507 /* Create the helper object */
1508 info = g_slice_new (UpdateAccountInfo);
1509 info->mail_op = self;
1510 info->account = store_account;
1511 info->transport_account = transport_account;
1512 info->callback = callback;
1513 info->user_data = user_data;
1515 /* Get the message size limit */
1516 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1517 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1518 if (info->max_size == 0)
1519 info->max_size = G_MAXINT;
1521 info->max_size = info->max_size * KB;
1523 /* Get per-account retrieval type */
1524 mgr = modest_runtime_get_account_mgr ();
1525 info->retrieve_type = modest_account_mgr_get_retrieve_type (mgr, account_name);
1527 /* Get per-account message amount retrieval limit */
1528 info->retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, account_name);
1529 if (info->retrieve_limit == 0)
1530 info->retrieve_limit = G_MAXINT;
1532 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1534 /* Set account busy */
1535 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1536 priv->account_name = g_strdup(account_name);
1538 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1544 g_object_unref (store_account);
1545 if (transport_account)
1546 g_object_unref (transport_account);
1547 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1549 callback (self, NULL, user_data);
1551 modest_mail_operation_notify_end (self);
1555 /* ******************************************************************* */
1556 /* ************************** STORE ACTIONS ************************* */
1557 /* ******************************************************************* */
1561 modest_mail_operation_create_folder (ModestMailOperation *self,
1562 TnyFolderStore *parent,
1565 ModestMailOperationPrivate *priv;
1566 TnyFolder *new_folder = NULL;
1568 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1569 g_return_val_if_fail (name, NULL);
1571 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1573 /* Check for already existing folder */
1574 if (modest_tny_folder_has_subfolder_with_name (parent, name)) {
1575 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1576 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1577 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1578 _CS("ckdg_ib_folder_already_exists"));
1582 if (TNY_IS_FOLDER (parent)) {
1583 /* Check folder rules */
1584 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1585 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1586 /* Set status failed and set an error */
1587 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1588 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1589 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1590 _("mail_in_ui_folder_create_error"));
1594 if (!strcmp (name, " ") || strchr (name, '/')) {
1595 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1596 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1597 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1598 _("mail_in_ui_folder_create_error"));
1602 /* Create the folder */
1603 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1604 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1606 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1609 /* Notify about operation end */
1610 modest_mail_operation_notify_end (self);
1616 modest_mail_operation_remove_folder (ModestMailOperation *self,
1618 gboolean remove_to_trash)
1620 TnyAccount *account;
1621 ModestMailOperationPrivate *priv;
1622 ModestTnyFolderRules rules;
1624 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1625 g_return_if_fail (TNY_IS_FOLDER (folder));
1627 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1629 /* Check folder rules */
1630 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1631 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1632 /* Set status failed and set an error */
1633 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1634 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1635 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1636 _("mail_in_ui_folder_delete_error"));
1640 /* Get the account */
1641 account = modest_tny_folder_get_account (folder);
1642 priv->account = g_object_ref(account);
1644 /* Delete folder or move to trash */
1645 if (remove_to_trash) {
1646 TnyFolder *trash_folder = NULL;
1647 trash_folder = modest_tny_account_get_special_folder (account,
1648 TNY_FOLDER_TYPE_TRASH);
1649 /* TODO: error_handling */
1651 modest_mail_operation_xfer_folder (self, folder,
1652 TNY_FOLDER_STORE (trash_folder),
1654 g_object_unref (trash_folder);
1657 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1659 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1660 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1663 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1666 g_object_unref (G_OBJECT (parent));
1668 g_object_unref (G_OBJECT (account));
1671 /* Notify about operation end */
1672 modest_mail_operation_notify_end (self);
1676 transfer_folder_status_cb (GObject *obj,
1680 ModestMailOperation *self;
1681 ModestMailOperationPrivate *priv;
1682 ModestMailOperationState *state;
1683 XFerMsgAsyncHelper *helper;
1685 g_return_if_fail (status != NULL);
1686 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1688 helper = (XFerMsgAsyncHelper *) user_data;
1689 g_return_if_fail (helper != NULL);
1691 self = helper->mail_op;
1692 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1694 priv->done = status->position;
1695 priv->total = status->of_total;
1697 state = modest_mail_operation_clone_state (self);
1699 /* This is not a GDK lock because we are a Tinymail callback
1700 * which is already GDK locked by Tinymail */
1702 /* no gdk_threads_enter (), CHECKED */
1704 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1706 /* no gdk_threads_leave (), CHECKED */
1708 g_slice_free (ModestMailOperationState, state);
1713 transfer_folder_cb (TnyFolder *folder,
1715 TnyFolderStore *into,
1716 TnyFolder *new_folder,
1720 XFerMsgAsyncHelper *helper;
1721 ModestMailOperation *self = NULL;
1722 ModestMailOperationPrivate *priv = NULL;
1724 helper = (XFerMsgAsyncHelper *) user_data;
1725 g_return_if_fail (helper != NULL);
1727 self = helper->mail_op;
1728 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1731 priv->error = g_error_copy (err);
1733 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1734 } else if (cancelled) {
1735 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1736 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1737 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1738 _("Transference of %s was cancelled."),
1739 tny_folder_get_name (folder));
1742 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1745 /* Notify about operation end */
1746 modest_mail_operation_notify_end (self);
1748 /* If user defined callback function was defined, call it */
1749 if (helper->user_callback) {
1751 /* This is not a GDK lock because we are a Tinymail callback
1752 * which is already GDK locked by Tinymail */
1754 /* no gdk_threads_enter (), CHECKED */
1755 helper->user_callback (self, helper->user_data);
1756 /* no gdk_threads_leave () , CHECKED */
1760 g_object_unref (helper->mail_op);
1761 g_slice_free (XFerMsgAsyncHelper, helper);
1766 * This function checks if the new name is a valid name for our local
1767 * folders account. The new name could not be the same than then name
1768 * of any of the mandatory local folders
1770 * We can not rely on tinymail because tinymail does not check the
1771 * name of the virtual folders that the account could have in the case
1772 * that we're doing a rename (because it directly calls Camel which
1773 * knows nothing about our virtual folders).
1775 * In the case of an actual copy/move (i.e. move/copy a folder between
1776 * accounts) tinymail uses the tny_folder_store_create_account which
1777 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1778 * checks the new name of the folder, so this call in that case
1779 * wouldn't be needed. *But* NOTE that if tinymail changes its
1780 * implementation (if folder transfers within the same account is no
1781 * longer implemented as a rename) this call will allow Modest to work
1784 * If the new name is not valid, this function will set the status to
1785 * failed and will set also an error in the mail operation
1788 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1789 TnyFolderStore *into,
1790 const gchar *new_name)
1792 if (TNY_IS_ACCOUNT (into) &&
1793 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1794 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1796 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1797 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1798 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1799 _("ckdg_ib_folder_already_exists"));
1806 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1808 TnyFolderStore *parent,
1809 gboolean delete_original,
1810 XferAsyncUserCallback user_callback,
1813 ModestMailOperationPrivate *priv = NULL;
1814 ModestTnyFolderRules parent_rules = 0, rules;
1815 XFerMsgAsyncHelper *helper = NULL;
1816 const gchar *folder_name = NULL;
1817 const gchar *error_msg;
1819 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1820 g_return_if_fail (TNY_IS_FOLDER (folder));
1821 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1823 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1824 folder_name = tny_folder_get_name (folder);
1826 /* Set the error msg */
1827 error_msg = _("mail_in_ui_folder_move_target_error");
1829 /* Get account and set it into mail_operation */
1830 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1831 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1833 /* Get folder rules */
1834 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1835 if (TNY_IS_FOLDER (parent))
1836 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1838 /* Apply operation constraints */
1839 if ((gpointer) parent == (gpointer) folder ||
1840 (!TNY_IS_FOLDER_STORE (parent)) ||
1841 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1844 } else if (TNY_IS_FOLDER (parent) &&
1845 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1849 } else if (TNY_IS_FOLDER (parent) &&
1850 TNY_IS_FOLDER_STORE (folder) &&
1851 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1852 TNY_FOLDER_STORE (folder))) {
1853 /* Do not move a parent into a child */
1855 } else if (TNY_IS_FOLDER_STORE (parent) &&
1856 modest_tny_folder_has_subfolder_with_name (parent, folder_name)) {
1857 /* Check that the new folder name is not used by any
1860 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1861 /* Check that the new folder name is not used by any
1862 special local folder */
1865 /* Create the helper */
1866 helper = g_slice_new0 (XFerMsgAsyncHelper);
1867 helper->mail_op = g_object_ref (self);
1868 helper->dest_folder = NULL;
1869 helper->headers = NULL;
1870 helper->user_callback = user_callback;
1871 helper->user_data = user_data;
1873 /* Move/Copy folder */
1874 tny_folder_copy_async (folder,
1876 tny_folder_get_name (folder),
1879 transfer_folder_status_cb,
1885 /* Set status failed and set an error */
1886 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1887 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1888 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1891 /* Call the user callback if exists */
1893 user_callback (self, user_data);
1895 /* Notify the queue */
1896 modest_mail_operation_notify_end (self);
1900 modest_mail_operation_rename_folder (ModestMailOperation *self,
1904 ModestMailOperationPrivate *priv;
1905 ModestTnyFolderRules rules;
1906 XFerMsgAsyncHelper *helper;
1908 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1909 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1910 g_return_if_fail (name);
1912 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1914 /* Get account and set it into mail_operation */
1915 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1917 /* Check folder rules */
1918 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1919 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1920 /* Set status failed and set an error */
1921 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1922 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1923 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1924 _("FIXME: unable to rename"));
1926 /* Notify about operation end */
1927 modest_mail_operation_notify_end (self);
1928 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1929 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1930 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1931 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1932 _("FIXME: unable to rename"));
1933 /* Notify about operation end */
1934 modest_mail_operation_notify_end (self);
1936 TnyFolderStore *into;
1938 into = tny_folder_get_folder_store (folder);
1940 /* Check that the new folder name is not used by any
1941 special local folder */
1942 if (new_name_valid_if_local_account (priv, into, name)) {
1943 /* Create the helper */
1944 helper = g_slice_new0 (XFerMsgAsyncHelper);
1945 helper->mail_op = g_object_ref(self);
1946 helper->dest_folder = NULL;
1947 helper->headers = NULL;
1948 helper->user_callback = NULL;
1949 helper->user_data = NULL;
1951 /* Rename. Camel handles folder subscription/unsubscription */
1952 tny_folder_copy_async (folder, into, name, TRUE,
1954 transfer_folder_status_cb,
1957 modest_mail_operation_notify_end (self);
1959 g_object_unref (into);
1963 /* ******************************************************************* */
1964 /* ************************** MSG ACTIONS ************************* */
1965 /* ******************************************************************* */
1967 void modest_mail_operation_get_msg (ModestMailOperation *self,
1969 GetMsgAsyncUserCallback user_callback,
1972 GetMsgAsyncHelper *helper = NULL;
1974 ModestMailOperationPrivate *priv;
1976 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1977 g_return_if_fail (TNY_IS_HEADER (header));
1979 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1980 folder = tny_header_get_folder (header);
1982 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1984 /* Get message from folder */
1986 /* Get account and set it into mail_operation */
1987 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1989 /* Check for cached messages */
1990 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
1991 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1993 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1995 helper = g_slice_new0 (GetMsgAsyncHelper);
1996 helper->mail_op = self;
1997 helper->user_callback = user_callback;
1998 helper->user_data = user_data;
1999 helper->header = g_object_ref (header);
2001 // The callback's reference so that the mail op is not
2002 // finalized until the async operation is completed even if
2003 // the user canceled the request meanwhile.
2004 g_object_ref (G_OBJECT (helper->mail_op));
2006 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
2008 g_object_unref (G_OBJECT (folder));
2010 /* Set status failed and set an error */
2011 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2012 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2013 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2014 _("Error trying to get a message. No folder found for header"));
2016 /* Notify the queue */
2017 modest_mail_operation_notify_end (self);
2022 get_msg_cb (TnyFolder *folder,
2028 GetMsgAsyncHelper *helper = NULL;
2029 ModestMailOperation *self = NULL;
2030 ModestMailOperationPrivate *priv = NULL;
2032 helper = (GetMsgAsyncHelper *) user_data;
2033 g_return_if_fail (helper != NULL);
2034 self = helper->mail_op;
2035 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2036 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2038 /* Check errors and cancel */
2040 priv->error = g_error_copy (error);
2041 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2042 } else if (cancelled) {
2043 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2044 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2045 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2046 _("Error trying to refresh the contents of %s"),
2047 tny_folder_get_name (folder));
2049 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2052 /* If user defined callback function was defined, call it even
2053 if the operation failed*/
2054 if (helper->user_callback) {
2055 /* This is not a GDK lock because we are a Tinymail callback
2056 * which is already GDK locked by Tinymail */
2058 /* no gdk_threads_enter (), CHECKED */
2059 helper->user_callback (self, helper->header, msg, helper->user_data);
2060 /* no gdk_threads_leave (), CHECKED */
2063 /* Notify about operation end */
2064 modest_mail_operation_notify_end (self);
2066 g_object_unref (helper->mail_op);
2067 g_object_unref (helper->header);
2068 g_slice_free (GetMsgAsyncHelper, helper);
2073 get_msg_status_cb (GObject *obj,
2077 GetMsgAsyncHelper *helper = NULL;
2078 ModestMailOperation *self;
2079 ModestMailOperationPrivate *priv;
2080 ModestMailOperationState *state;
2082 g_return_if_fail (status != NULL);
2083 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2085 helper = (GetMsgAsyncHelper *) user_data;
2086 g_return_if_fail (helper != NULL);
2088 self = helper->mail_op;
2089 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2094 state = modest_mail_operation_clone_state (self);
2095 state->bytes_done = status->position;
2096 state->bytes_total = status->of_total;
2098 /* This is not a GDK lock because we are a Tinymail callback
2099 * which is already GDK locked by Tinymail */
2101 /* no gdk_threads_enter (), CHECKED */
2102 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2103 /* no gdk_threads_leave (), CHECKED */
2105 g_slice_free (ModestMailOperationState, state);
2108 /****************************************************/
2110 ModestMailOperation *mail_op;
2112 GetMsgAsyncUserCallback user_callback;
2114 GDestroyNotify notify;
2118 GetMsgAsyncUserCallback user_callback;
2122 ModestMailOperation *mail_op;
2123 } NotifyGetMsgsInfo;
2127 * Used by get_msgs_full_thread to call the user_callback for each
2128 * message that has been read
2131 notify_get_msgs_full (gpointer data)
2133 NotifyGetMsgsInfo *info;
2135 info = (NotifyGetMsgsInfo *) data;
2137 /* This is a GDK lock because we are an idle callback and
2138 * because info->user_callback can contain Gtk+ code */
2140 gdk_threads_enter (); /* CHECKED */
2141 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2142 gdk_threads_leave (); /* CHECKED */
2144 g_slice_free (NotifyGetMsgsInfo, info);
2150 * Used by get_msgs_full_thread to free al the thread resources and to
2151 * call the destroy function for the passed user_data
2154 get_msgs_full_destroyer (gpointer data)
2156 GetFullMsgsInfo *info;
2158 info = (GetFullMsgsInfo *) data;
2162 /* This is a GDK lock because we are an idle callback and
2163 * because info->notify can contain Gtk+ code */
2165 gdk_threads_enter (); /* CHECKED */
2166 info->notify (info->user_data);
2167 gdk_threads_leave (); /* CHECKED */
2171 g_object_unref (info->headers);
2172 g_slice_free (GetFullMsgsInfo, info);
2178 get_msgs_full_thread (gpointer thr_user_data)
2180 GetFullMsgsInfo *info;
2181 ModestMailOperationPrivate *priv = NULL;
2182 TnyIterator *iter = NULL;
2184 info = (GetFullMsgsInfo *) thr_user_data;
2185 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2187 iter = tny_list_create_iterator (info->headers);
2188 while (!tny_iterator_is_done (iter)) {
2192 header = TNY_HEADER (tny_iterator_get_current (iter));
2193 folder = tny_header_get_folder (header);
2195 /* Check for cached messages */
2196 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2197 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2199 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2201 /* Get message from folder */
2204 /* The callback will call it per each header */
2205 msg = tny_folder_get_msg (folder, header, &(priv->error));
2208 ModestMailOperationState *state;
2213 /* notify progress */
2214 state = modest_mail_operation_clone_state (info->mail_op);
2215 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2216 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2217 pair, (GDestroyNotify) modest_pair_free);
2219 /* The callback is the responsible for
2220 freeing the message */
2221 if (info->user_callback) {
2222 NotifyGetMsgsInfo *info_notify;
2223 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2224 info_notify->user_callback = info->user_callback;
2225 info_notify->mail_op = info->mail_op;
2226 info_notify->header = g_object_ref (header);
2227 info_notify->msg = g_object_ref (msg);
2228 info_notify->user_data = info->user_data;
2229 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2230 notify_get_msgs_full,
2233 g_object_unref (msg);
2236 /* Set status failed and set an error */
2237 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2238 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2239 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2240 "Error trying to get a message. No folder found for header");
2244 g_object_unref (header);
2246 tny_iterator_next (iter);
2249 /* Set operation status */
2250 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2251 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2253 /* Notify about operation end */
2254 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2256 /* Free thread resources. Will be called after all previous idles */
2257 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2263 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2264 TnyList *header_list,
2265 GetMsgAsyncUserCallback user_callback,
2267 GDestroyNotify notify)
2269 TnyHeader *header = NULL;
2270 TnyFolder *folder = NULL;
2272 ModestMailOperationPrivate *priv = NULL;
2273 GetFullMsgsInfo *info = NULL;
2274 gboolean size_ok = TRUE;
2276 TnyIterator *iter = NULL;
2278 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2280 /* Init mail operation */
2281 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2282 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2284 priv->total = tny_list_get_length(header_list);
2286 /* Get account and set it into mail_operation */
2287 if (tny_list_get_length (header_list) >= 1) {
2288 iter = tny_list_create_iterator (header_list);
2289 header = TNY_HEADER (tny_iterator_get_current (iter));
2291 folder = tny_header_get_folder (header);
2293 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2295 g_object_unref (folder);
2298 g_object_unref (header);
2301 if (tny_list_get_length (header_list) == 1) {
2302 g_object_unref (iter);
2307 /* Get msg size limit */
2308 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2309 MODEST_CONF_MSG_SIZE_LIMIT,
2312 g_clear_error (&(priv->error));
2313 max_size = G_MAXINT;
2315 max_size = max_size * KB;
2318 /* Check message size limits. If there is only one message
2319 always retrieve it */
2321 while (!tny_iterator_is_done (iter) && size_ok) {
2322 header = TNY_HEADER (tny_iterator_get_current (iter));
2324 if (tny_header_get_message_size (header) >= max_size)
2326 g_object_unref (header);
2329 tny_iterator_next (iter);
2331 g_object_unref (iter);
2335 /* Create the info */
2336 info = g_slice_new0 (GetFullMsgsInfo);
2337 info->mail_op = self;
2338 info->user_callback = user_callback;
2339 info->user_data = user_data;
2340 info->headers = g_object_ref (header_list);
2341 info->notify = notify;
2343 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2345 /* Set status failed and set an error */
2346 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2347 /* FIXME: the error msg is different for pop */
2348 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2349 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2350 _("emev_ni_ui_imap_msg_size_exceed_error"));
2351 /* Remove from queue and free resources */
2352 modest_mail_operation_notify_end (self);
2360 modest_mail_operation_remove_msg (ModestMailOperation *self,
2362 gboolean remove_to_trash /*ignored*/)
2365 ModestMailOperationPrivate *priv;
2367 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2368 g_return_if_fail (TNY_IS_HEADER (header));
2370 if (remove_to_trash)
2371 g_warning ("remove to trash is not implemented");
2373 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2374 folder = tny_header_get_folder (header);
2376 /* Get account and set it into mail_operation */
2377 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2379 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2381 /* remove message from folder */
2382 tny_folder_remove_msg (folder, header, &(priv->error));
2384 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2385 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2387 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2388 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* FALSE --> don't expunge *\/ */
2389 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2390 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2391 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* TRUE --> dont expunge *\/ */
2392 tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2395 /* tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /\* TRUE --> expunge *\/ */
2396 tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2402 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2404 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2407 g_object_unref (G_OBJECT (folder));
2409 /* Notify about operation end */
2410 modest_mail_operation_notify_end (self);
2414 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2416 gboolean remove_to_trash /*ignored*/)
2419 ModestMailOperationPrivate *priv;
2420 TnyIterator *iter = NULL;
2421 TnyHeader *header = NULL;
2423 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2424 g_return_if_fail (TNY_IS_LIST (headers));
2426 if (remove_to_trash)
2427 g_warning ("remove to trash is not implemented");
2429 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2431 /* Get folder from first header and sync it */
2432 iter = tny_list_create_iterator (headers);
2433 header = TNY_HEADER (tny_iterator_get_current (iter));
2434 folder = tny_header_get_folder (header);
2436 /* Get account and set it into mail_operation */
2437 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2439 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2441 /* remove message from folder */
2442 tny_folder_remove_msgs (folder, headers, &(priv->error));
2444 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2445 TNY_IS_CAMEL_POP_FOLDER (folder))
2446 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> don't expunge */
2449 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2455 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2457 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2460 g_object_unref (header);
2461 g_object_unref (iter);
2462 g_object_unref (G_OBJECT (folder));
2464 /* Notify about operation end */
2465 modest_mail_operation_notify_end (self);
2470 transfer_msgs_status_cb (GObject *obj,
2474 XFerMsgAsyncHelper *helper = NULL;
2475 ModestMailOperation *self;
2476 ModestMailOperationPrivate *priv;
2477 ModestMailOperationState *state;
2480 g_return_if_fail (status != NULL);
2481 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2483 helper = (XFerMsgAsyncHelper *) user_data;
2484 g_return_if_fail (helper != NULL);
2486 self = helper->mail_op;
2487 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2489 priv->done = status->position;
2490 priv->total = status->of_total;
2492 state = modest_mail_operation_clone_state (self);
2494 /* This is not a GDK lock because we are a Tinymail callback and
2495 * Tinymail already acquires the Gdk lock */
2497 /* no gdk_threads_enter (), CHECKED */
2499 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2501 /* no gdk_threads_leave (), CHECKED */
2503 g_slice_free (ModestMailOperationState, state);
2508 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2510 XFerMsgAsyncHelper *helper;
2511 ModestMailOperation *self;
2512 ModestMailOperationPrivate *priv;
2513 TnyIterator *iter = NULL;
2514 TnyHeader *header = NULL;
2516 helper = (XFerMsgAsyncHelper *) user_data;
2517 self = helper->mail_op;
2519 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2522 priv->error = g_error_copy (err);
2524 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2525 } else if (cancelled) {
2526 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2527 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2528 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2529 _("Error trying to refresh the contents of %s"),
2530 tny_folder_get_name (folder));
2533 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2535 /* Update folder counts */
2536 tny_folder_poke_status (folder);
2537 tny_folder_poke_status (helper->dest_folder);
2541 /* Mark headers as deleted and seen */
2542 if ((helper->delete) &&
2543 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2544 iter = tny_list_create_iterator (helper->headers);
2545 while (!tny_iterator_is_done (iter)) {
2546 header = TNY_HEADER (tny_iterator_get_current (iter));
2547 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2548 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2549 g_object_unref (header);
2551 tny_iterator_next (iter);
2557 /* Notify about operation end */
2558 modest_mail_operation_notify_end (self);
2560 /* If user defined callback function was defined, call it */
2561 if (helper->user_callback) {
2562 /* This is not a GDK lock because we are a Tinymail callback and
2563 * Tinymail already acquires the Gdk lock */
2565 /* no gdk_threads_enter (), CHECKED */
2566 helper->user_callback (self, helper->user_data);
2567 /* no gdk_threads_leave (), CHECKED */
2571 if (helper->headers)
2572 g_object_unref (helper->headers);
2573 if (helper->dest_folder)
2574 g_object_unref (helper->dest_folder);
2575 if (helper->mail_op)
2576 g_object_unref (helper->mail_op);
2578 g_object_unref (folder);
2580 g_object_unref (iter);
2581 g_slice_free (XFerMsgAsyncHelper, helper);
2585 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2588 gboolean delete_original,
2589 XferAsyncUserCallback user_callback,
2592 ModestMailOperationPrivate *priv = NULL;
2593 TnyIterator *iter = NULL;
2594 TnyFolder *src_folder = NULL;
2595 XFerMsgAsyncHelper *helper = NULL;
2596 TnyHeader *header = NULL;
2597 ModestTnyFolderRules rules = 0;
2599 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2600 g_return_if_fail (TNY_IS_LIST (headers));
2601 g_return_if_fail (TNY_IS_FOLDER (folder));
2603 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2606 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2608 /* Apply folder rules */
2609 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2610 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2611 /* Set status failed and set an error */
2612 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2613 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2614 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2615 _CS("ckct_ib_unable_to_paste_here"));
2616 /* Notify the queue */
2617 modest_mail_operation_notify_end (self);
2621 /* Get source folder */
2622 iter = tny_list_create_iterator (headers);
2623 header = TNY_HEADER (tny_iterator_get_current (iter));
2625 src_folder = tny_header_get_folder (header);
2626 g_object_unref (header);
2629 g_object_unref (iter);
2631 /* Check folder source and destination */
2632 if (src_folder == folder) {
2633 /* Set status failed and set an error */
2634 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2635 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2636 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2637 _("mcen_ib_unable_to_copy_samefolder"));
2639 /* Notify the queue */
2640 modest_mail_operation_notify_end (self);
2643 g_object_unref (src_folder);
2647 /* Create the helper */
2648 helper = g_slice_new0 (XFerMsgAsyncHelper);
2649 helper->mail_op = g_object_ref(self);
2650 helper->dest_folder = g_object_ref(folder);
2651 helper->headers = g_object_ref(headers);
2652 helper->user_callback = user_callback;
2653 helper->user_data = user_data;
2654 helper->delete = delete_original;
2656 /* Get account and set it into mail_operation */
2657 priv->account = modest_tny_folder_get_account (src_folder);
2659 /* Transfer messages */
2660 tny_folder_transfer_msgs_async (src_folder,
2665 transfer_msgs_status_cb,
2671 on_refresh_folder (TnyFolder *folder,
2676 RefreshAsyncHelper *helper = NULL;
2677 ModestMailOperation *self = NULL;
2678 ModestMailOperationPrivate *priv = NULL;
2680 helper = (RefreshAsyncHelper *) user_data;
2681 self = helper->mail_op;
2682 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2684 g_return_if_fail(priv!=NULL);
2687 priv->error = g_error_copy (error);
2688 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2689 printf("DEBUG: %s: Operation error:\n %s", __FUNCTION__,
2695 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2696 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2697 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2698 _("Error trying to refresh the contents of %s"),
2699 tny_folder_get_name (folder));
2700 printf("DEBUG: %s: Operation cancelled.\n", __FUNCTION__);
2704 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2706 /* Call user defined callback, if it exists */
2707 if (helper->user_callback) {
2709 /* This is not a GDK lock because we are a Tinymail callback and
2710 * Tinymail already acquires the Gdk lock */
2711 helper->user_callback (self, folder, helper->user_data);
2716 g_slice_free (RefreshAsyncHelper, helper);
2718 /* Notify about operation end */
2719 modest_mail_operation_notify_end (self);
2720 g_object_unref(self);
2724 on_refresh_folder_status_update (GObject *obj,
2728 RefreshAsyncHelper *helper = NULL;
2729 ModestMailOperation *self = NULL;
2730 ModestMailOperationPrivate *priv = NULL;
2731 ModestMailOperationState *state;
2733 g_return_if_fail (user_data != NULL);
2734 g_return_if_fail (status != NULL);
2735 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2737 helper = (RefreshAsyncHelper *) user_data;
2738 self = helper->mail_op;
2739 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2741 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2743 priv->done = status->position;
2744 priv->total = status->of_total;
2746 state = modest_mail_operation_clone_state (self);
2748 /* This is not a GDK lock because we are a Tinymail callback and
2749 * Tinymail already acquires the Gdk lock */
2750 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2752 g_slice_free (ModestMailOperationState, state);
2756 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2758 RefreshAsyncUserCallback user_callback,
2761 ModestMailOperationPrivate *priv = NULL;
2762 RefreshAsyncHelper *helper = NULL;
2764 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2766 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2768 /* Get account and set it into mail_operation */
2769 priv->account = modest_tny_folder_get_account (folder);
2771 /* Create the helper */
2772 helper = g_slice_new0 (RefreshAsyncHelper);
2773 helper->mail_op = g_object_ref(self);
2774 helper->user_callback = user_callback;
2775 helper->user_data = user_data;
2777 /* Refresh the folder. TODO: tinymail could issue a status
2778 updates before the callback call then this could happen. We
2779 must review the design */
2780 tny_folder_refresh_async (folder,
2782 on_refresh_folder_status_update,
2788 * It's used by the mail operation queue to notify the observers
2789 * attached to that signal that the operation finished. We need to use
2790 * that because tinymail does not give us the progress of a given
2791 * operation when it finishes (it directly calls the operation
2795 modest_mail_operation_notify_end (ModestMailOperation *self)
2797 ModestMailOperationState *state;
2798 ModestMailOperationPrivate *priv = NULL;
2800 g_return_if_fail (self);
2802 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2804 /* Set the account back to not busy */
2805 if (priv->account_name) {
2806 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2807 priv->account_name, FALSE);
2808 g_free(priv->account_name);
2809 priv->account_name = NULL;
2812 /* Notify the observers about the mail operation end */
2813 /* We do not wrapp this emission because we assume that this
2814 function is always called from within the main lock */
2815 state = modest_mail_operation_clone_state (self);
2816 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2817 g_slice_free (ModestMailOperationState, state);