1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-camel-pop-store-account.h>
38 #include <tny-camel-pop-folder.h>
39 #include <tny-camel-imap-folder.h>
40 #include <tny-camel-mem-stream.h>
41 #include <tny-simple-list.h>
42 #include <tny-send-queue.h>
43 #include <tny-status.h>
44 #include <tny-folder-observer.h>
45 #include <camel/camel-stream-mem.h>
46 #include <glib/gi18n.h>
47 #include "modest-platform.h"
48 #include <modest-tny-account.h>
49 #include <modest-tny-send-queue.h>
50 #include <modest-runtime.h>
51 #include "modest-text-utils.h"
52 #include "modest-tny-msg.h"
53 #include "modest-tny-folder.h"
54 #include "modest-tny-account-store.h"
55 #include "modest-tny-platform-factory.h"
56 #include "modest-marshal.h"
57 #include "modest-error.h"
58 #include "modest-mail-operation.h"
63 * Remove all these #ifdef stuff when the tinymail's idle calls become
66 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
68 /* 'private'/'protected' functions */
69 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
70 static void modest_mail_operation_init (ModestMailOperation *obj);
71 static void modest_mail_operation_finalize (GObject *obj);
73 static void get_msg_cb (TnyFolder *folder,
79 static void get_msg_status_cb (GObject *obj,
83 static void modest_mail_operation_notify_end (ModestMailOperation *self);
85 enum _ModestMailOperationSignals
87 PROGRESS_CHANGED_SIGNAL,
92 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
93 struct _ModestMailOperationPrivate {
100 ErrorCheckingUserCallback error_checking;
101 gpointer error_checking_user_data;
102 ModestMailOperationStatus status;
103 ModestMailOperationTypeOperation op_type;
106 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
107 MODEST_TYPE_MAIL_OPERATION, \
108 ModestMailOperationPrivate))
110 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
111 priv->status = new_status;\
114 typedef struct _GetMsgAsyncHelper {
115 ModestMailOperation *mail_op;
117 GetMsgAsyncUserCallback user_callback;
121 typedef struct _RefreshAsyncHelper {
122 ModestMailOperation *mail_op;
123 RefreshAsyncUserCallback user_callback;
125 } RefreshAsyncHelper;
127 typedef struct _XFerMsgAsyncHelper
129 ModestMailOperation *mail_op;
131 TnyFolder *dest_folder;
132 XferMsgsAsynUserCallback user_callback;
135 } XFerMsgAsyncHelper;
137 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
141 static void modest_mail_operation_create_msg (ModestMailOperation *self,
142 const gchar *from, const gchar *to,
143 const gchar *cc, const gchar *bcc,
144 const gchar *subject, const gchar *plain_body,
145 const gchar *html_body, const GList *attachments_list,
146 TnyHeaderFlags priority_flags,
147 ModestMailOperationCreateMsgCallback callback,
150 static gboolean idle_notify_queue (gpointer data);
153 ModestMailOperation *mail_op;
161 GList *attachments_list;
162 TnyHeaderFlags priority_flags;
163 ModestMailOperationCreateMsgCallback callback;
169 ModestMailOperation *mail_op;
171 ModestMailOperationCreateMsgCallback callback;
176 static GObjectClass *parent_class = NULL;
178 static guint signals[NUM_SIGNALS] = {0};
181 modest_mail_operation_get_type (void)
183 static GType my_type = 0;
185 static const GTypeInfo my_info = {
186 sizeof(ModestMailOperationClass),
187 NULL, /* base init */
188 NULL, /* base finalize */
189 (GClassInitFunc) modest_mail_operation_class_init,
190 NULL, /* class finalize */
191 NULL, /* class data */
192 sizeof(ModestMailOperation),
194 (GInstanceInitFunc) modest_mail_operation_init,
197 my_type = g_type_register_static (G_TYPE_OBJECT,
198 "ModestMailOperation",
205 modest_mail_operation_class_init (ModestMailOperationClass *klass)
207 GObjectClass *gobject_class;
208 gobject_class = (GObjectClass*) klass;
210 parent_class = g_type_class_peek_parent (klass);
211 gobject_class->finalize = modest_mail_operation_finalize;
213 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
216 * ModestMailOperation::progress-changed
217 * @self: the #MailOperation that emits the signal
218 * @user_data: user data set when the signal handler was connected
220 * Emitted when the progress of a mail operation changes
222 signals[PROGRESS_CHANGED_SIGNAL] =
223 g_signal_new ("progress-changed",
224 G_TYPE_FROM_CLASS (gobject_class),
226 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
228 g_cclosure_marshal_VOID__POINTER,
229 G_TYPE_NONE, 1, G_TYPE_POINTER);
234 modest_mail_operation_init (ModestMailOperation *obj)
236 ModestMailOperationPrivate *priv;
238 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
240 priv->account = NULL;
241 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
242 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
247 priv->error_checking = NULL;
248 priv->error_checking_user_data = NULL;
252 modest_mail_operation_finalize (GObject *obj)
254 ModestMailOperationPrivate *priv;
256 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
261 g_error_free (priv->error);
265 g_object_unref (priv->source);
269 g_object_unref (priv->account);
270 priv->account = NULL;
274 G_OBJECT_CLASS(parent_class)->finalize (obj);
278 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
281 ModestMailOperation *obj;
282 ModestMailOperationPrivate *priv;
284 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
285 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
287 priv->op_type = op_type;
289 priv->source = g_object_ref(source);
295 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
297 ErrorCheckingUserCallback error_handler,
300 ModestMailOperation *obj;
301 ModestMailOperationPrivate *priv;
303 obj = modest_mail_operation_new (op_type, source);
304 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
306 g_return_val_if_fail (error_handler != NULL, obj);
307 priv->error_checking = error_handler;
313 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
315 ModestMailOperationPrivate *priv;
317 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
318 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
320 if (priv->error_checking != NULL)
321 priv->error_checking (self, priv->error_checking_user_data);
325 ModestMailOperationTypeOperation
326 modest_mail_operation_get_type_operation (ModestMailOperation *self)
328 ModestMailOperationPrivate *priv;
330 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
332 return priv->op_type;
336 modest_mail_operation_is_mine (ModestMailOperation *self,
339 ModestMailOperationPrivate *priv;
341 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
342 if (priv->source == NULL) return FALSE;
344 return priv->source == me;
348 modest_mail_operation_get_source (ModestMailOperation *self)
350 ModestMailOperationPrivate *priv;
352 g_return_val_if_fail (self, NULL);
354 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
356 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
360 return g_object_ref (priv->source);
363 ModestMailOperationStatus
364 modest_mail_operation_get_status (ModestMailOperation *self)
366 ModestMailOperationPrivate *priv;
368 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
369 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
370 MODEST_MAIL_OPERATION_STATUS_INVALID);
372 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
374 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
375 return MODEST_MAIL_OPERATION_STATUS_INVALID;
382 modest_mail_operation_get_error (ModestMailOperation *self)
384 ModestMailOperationPrivate *priv;
386 g_return_val_if_fail (self, NULL);
387 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
389 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
392 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
400 modest_mail_operation_cancel (ModestMailOperation *self)
402 ModestMailOperationPrivate *priv;
403 gboolean canceled = FALSE;
405 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
407 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
409 /* Note that if we call cancel with an already canceled mail
410 operation the progress changed signal won't be emitted */
411 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
415 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
417 /* Cancel the mail operation. We need to wrap it between this
418 start/stop operations to allow following calls to the
420 g_return_val_if_fail (priv->account, FALSE);
421 tny_account_cancel (priv->account);
427 modest_mail_operation_get_task_done (ModestMailOperation *self)
429 ModestMailOperationPrivate *priv;
431 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
433 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
438 modest_mail_operation_get_task_total (ModestMailOperation *self)
440 ModestMailOperationPrivate *priv;
442 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
444 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
449 modest_mail_operation_is_finished (ModestMailOperation *self)
451 ModestMailOperationPrivate *priv;
452 gboolean retval = FALSE;
454 if (!MODEST_IS_MAIL_OPERATION (self)) {
455 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
459 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
461 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
462 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
463 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
464 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
474 modest_mail_operation_get_id (ModestMailOperation *self)
476 ModestMailOperationPrivate *priv;
478 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
480 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
485 modest_mail_operation_set_id (ModestMailOperation *self,
488 ModestMailOperationPrivate *priv;
490 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
492 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
497 * Creates an image of the current state of a mail operation, the
498 * caller must free it
500 static ModestMailOperationState *
501 modest_mail_operation_clone_state (ModestMailOperation *self)
503 ModestMailOperationState *state;
504 ModestMailOperationPrivate *priv;
506 /* FIXME: this should be fixed properly
508 * in some cases, priv was NULL, so checking here to
511 g_return_val_if_fail (self, NULL);
512 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
513 g_return_val_if_fail (priv, NULL);
518 state = g_slice_new (ModestMailOperationState);
520 state->status = priv->status;
521 state->op_type = priv->op_type;
522 state->done = priv->done;
523 state->total = priv->total;
524 state->finished = modest_mail_operation_is_finished (self);
525 state->bytes_done = 0;
526 state->bytes_total = 0;
531 /* ******************************************************************* */
532 /* ************************** SEND ACTIONS ************************* */
533 /* ******************************************************************* */
536 modest_mail_operation_send_mail (ModestMailOperation *self,
537 TnyTransportAccount *transport_account,
540 TnySendQueue *send_queue = NULL;
541 ModestMailOperationPrivate *priv;
543 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
544 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
545 g_return_if_fail (TNY_IS_MSG (msg));
547 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
549 /* Get account and set it into mail_operation */
550 priv->account = g_object_ref (transport_account);
554 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
555 if (!TNY_IS_SEND_QUEUE(send_queue)) {
556 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
557 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
558 "modest: could not find send queue for account\n");
560 /* TODO: connect to the msg-sent in order to know when
561 the mail operation is finished */
562 tny_send_queue_add (send_queue, msg, &(priv->error));
563 /* TODO: we're setting always success, do the check in
565 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
568 /* TODO: do this in the handler of the "msg-sent"
569 signal.Notify about operation end */
570 modest_mail_operation_notify_end (self);
574 idle_create_msg_cb (gpointer idle_data)
576 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
578 /* This is a GDK lock because we are an idle callback and
579 * info->callback can contain Gtk+ code */
581 gdk_threads_enter (); /* CHECKED */
582 info->callback (info->mail_op, info->msg, info->userdata);
583 gdk_threads_leave (); /* CHECKED */
585 g_object_unref (info->mail_op);
587 g_object_unref (info->msg);
588 g_slice_free (CreateMsgIdleInfo, info);
594 create_msg_thread (gpointer thread_data)
596 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
597 TnyMsg *new_msg = NULL;
598 ModestMailOperationPrivate *priv;
600 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
601 if (info->html_body == NULL) {
602 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
603 info->bcc, info->subject, info->plain_body,
604 info->attachments_list); /* FIXME: attachments */
606 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
607 info->bcc, info->subject, info->html_body,
608 info->plain_body, info->attachments_list);
613 /* Set priority flags in message */
614 header = tny_msg_get_header (new_msg);
615 if (info->priority_flags != 0)
616 tny_header_set_flags (header, info->priority_flags);
617 if (info->attachments_list != NULL) {
618 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
620 g_object_unref (G_OBJECT(header));
622 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
623 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
624 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
625 "modest: failed to create a new msg\n");
633 g_free (info->plain_body);
634 g_free (info->html_body);
635 g_free (info->subject);
636 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
637 g_list_free (info->attachments_list);
639 if (info->callback) {
640 CreateMsgIdleInfo *idle_info;
641 idle_info = g_slice_new0 (CreateMsgIdleInfo);
642 idle_info->mail_op = info->mail_op;
643 g_object_ref (info->mail_op);
644 idle_info->msg = new_msg;
646 g_object_ref (new_msg);
647 idle_info->callback = info->callback;
648 idle_info->userdata = info->userdata;
649 g_idle_add (idle_create_msg_cb, idle_info);
651 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
654 g_object_unref (info->mail_op);
655 g_slice_free (CreateMsgInfo, info);
660 modest_mail_operation_create_msg (ModestMailOperation *self,
661 const gchar *from, const gchar *to,
662 const gchar *cc, const gchar *bcc,
663 const gchar *subject, const gchar *plain_body,
664 const gchar *html_body,
665 const GList *attachments_list,
666 TnyHeaderFlags priority_flags,
667 ModestMailOperationCreateMsgCallback callback,
670 CreateMsgInfo *info = NULL;
672 info = g_slice_new0 (CreateMsgInfo);
673 info->mail_op = self;
676 info->from = g_strdup (from);
677 info->to = g_strdup (to);
678 info->cc = g_strdup (cc);
679 info->bcc = g_strdup (bcc);
680 info->subject = g_strdup (subject);
681 info->plain_body = g_strdup (plain_body);
682 info->html_body = g_strdup (html_body);
683 info->attachments_list = g_list_copy ((GList *) attachments_list);
684 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
685 info->priority_flags = priority_flags;
687 info->callback = callback;
688 info->userdata = userdata;
690 g_thread_create (create_msg_thread, info, FALSE, NULL);
695 TnyTransportAccount *transport_account;
700 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
704 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
705 TnyFolder *draft_folder = NULL;
706 TnyFolder *outbox_folder = NULL;
713 /* Call mail operation */
714 modest_mail_operation_send_mail (self, info->transport_account, msg);
716 /* Remove old mail from its source folder */
717 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
718 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_OUTBOX);
719 if (info->draft_msg != NULL) {
720 TnyFolder *folder = NULL;
721 TnyFolder *src_folder = NULL;
722 TnyFolderType folder_type;
723 folder = tny_msg_get_folder (info->draft_msg);
724 if (folder == NULL) goto end;
725 folder_type = modest_tny_folder_guess_folder_type (folder);
726 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
727 src_folder = outbox_folder;
729 src_folder = draft_folder;
731 /* Note: This can fail (with a warning) if the message is not really already in a folder,
732 * because this function requires it to have a UID. */
733 header = tny_msg_get_header (info->draft_msg);
734 tny_folder_remove_msg (src_folder, header, NULL);
735 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
736 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
737 g_object_unref (header);
738 g_object_unref (folder);
743 g_object_unref (info->draft_msg);
745 g_object_unref (draft_folder);
747 g_object_unref (outbox_folder);
748 if (info->transport_account)
749 g_object_unref (info->transport_account);
750 g_slice_free (SendNewMailInfo, info);
751 modest_mail_operation_notify_end (self);
755 modest_mail_operation_send_new_mail (ModestMailOperation *self,
756 TnyTransportAccount *transport_account,
758 const gchar *from, const gchar *to,
759 const gchar *cc, const gchar *bcc,
760 const gchar *subject, const gchar *plain_body,
761 const gchar *html_body,
762 const GList *attachments_list,
763 TnyHeaderFlags priority_flags)
765 ModestMailOperationPrivate *priv = NULL;
766 SendNewMailInfo *info;
768 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
769 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
771 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
773 /* Check parametters */
775 /* Set status failed and set an error */
776 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
777 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
778 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
779 _("Error trying to send a mail. You need to set at least one recipient"));
782 info = g_slice_new0 (SendNewMailInfo);
783 info->transport_account = transport_account;
784 if (transport_account)
785 g_object_ref (transport_account);
786 info->draft_msg = draft_msg;
788 g_object_ref (draft_msg);
789 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
790 attachments_list, priority_flags,
791 modest_mail_operation_send_new_mail_cb, info);
797 TnyTransportAccount *transport_account;
799 ModestMsgEditWindow *edit_window;
803 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
807 TnyFolder *src_folder = NULL;
808 TnyFolder *folder = NULL;
809 TnyHeader *header = NULL;
810 ModestMailOperationPrivate *priv = NULL;
811 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
813 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
815 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
816 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
817 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
818 "modest: failed to create a new msg\n");
822 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
824 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
825 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
826 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
827 "modest: failed to create a new msg\n");
832 tny_folder_add_msg (folder, msg, &(priv->error));
834 if ((!priv->error) && (info->draft_msg != NULL)) {
835 header = tny_msg_get_header (info->draft_msg);
836 src_folder = tny_header_get_folder (header);
837 /* Remove the old draft expunging it */
838 tny_folder_remove_msg (src_folder, header, NULL);
839 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
840 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
841 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */
842 g_object_unref (header);
846 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
848 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
850 if (info->edit_window)
851 modest_msg_edit_window_set_draft (info->edit_window, msg);
856 g_object_unref (G_OBJECT(folder));
858 g_object_unref (G_OBJECT(src_folder));
859 if (info->edit_window)
860 g_object_unref (G_OBJECT(info->edit_window));
862 g_object_unref (G_OBJECT (info->draft_msg));
863 if (info->transport_account)
864 g_object_unref (G_OBJECT(info->transport_account));
865 g_slice_free (SaveToDraftsInfo, info);
867 modest_mail_operation_notify_end (self);
871 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
872 TnyTransportAccount *transport_account,
874 ModestMsgEditWindow *edit_window,
875 const gchar *from, const gchar *to,
876 const gchar *cc, const gchar *bcc,
877 const gchar *subject, const gchar *plain_body,
878 const gchar *html_body,
879 const GList *attachments_list,
880 TnyHeaderFlags priority_flags)
882 ModestMailOperationPrivate *priv = NULL;
883 SaveToDraftsInfo *info = NULL;
885 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
886 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
888 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
890 /* Get account and set it into mail_operation */
891 priv->account = g_object_ref (transport_account);
893 info = g_slice_new0 (SaveToDraftsInfo);
894 info->transport_account = g_object_ref (transport_account);
895 info->draft_msg = draft_msg;
897 g_object_ref (draft_msg);
898 info->edit_window = edit_window;
900 g_object_ref (edit_window);
902 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
903 attachments_list, priority_flags,
904 modest_mail_operation_save_to_drafts_cb, info);
910 ModestMailOperation *mail_op;
911 TnyStoreAccount *account;
912 TnyTransportAccount *transport_account;
915 gchar *retrieve_type;
917 UpdateAccountCallback callback;
924 ModestMailOperation *mail_op;
925 TnyMimePart *mime_part;
927 GetMimePartSizeCallback callback;
929 } GetMimePartSizeInfo;
931 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
932 /* We use this folder observer to track the headers that have been
933 * added to a folder */
936 TnyList *new_headers;
937 } InternalFolderObserver;
941 } InternalFolderObserverClass;
943 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
945 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
946 internal_folder_observer,
948 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
952 foreach_add_item (gpointer header, gpointer user_data)
954 tny_list_prepend (TNY_LIST (user_data),
955 g_object_ref (G_OBJECT (header)));
958 /* This is the method that looks for new messages in a folder */
960 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
962 InternalFolderObserver *derived = (InternalFolderObserver *)self;
964 TnyFolderChangeChanged changed;
966 changed = tny_folder_change_get_changed (change);
968 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
971 /* Get added headers */
972 list = tny_simple_list_new ();
973 tny_folder_change_get_added_headers (change, list);
975 /* Add them to the folder observer */
976 tny_list_foreach (list, foreach_add_item,
977 derived->new_headers);
979 g_object_unref (G_OBJECT (list));
984 internal_folder_observer_init (InternalFolderObserver *self)
986 self->new_headers = tny_simple_list_new ();
989 internal_folder_observer_finalize (GObject *object)
991 InternalFolderObserver *self;
993 self = (InternalFolderObserver *) object;
994 g_object_unref (self->new_headers);
996 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
999 tny_folder_observer_init (TnyFolderObserverIface *iface)
1001 iface->update_func = internal_folder_observer_update;
1004 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1006 GObjectClass *object_class;
1008 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1009 object_class = (GObjectClass*) klass;
1010 object_class->finalize = internal_folder_observer_finalize;
1016 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
1019 TnyList *folders = tny_simple_list_new ();
1021 tny_folder_store_get_folders (store, folders, query, NULL);
1022 iter = tny_list_create_iterator (folders);
1024 while (!tny_iterator_is_done (iter)) {
1026 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1028 tny_list_prepend (all_folders, G_OBJECT (folder));
1029 recurse_folders (folder, query, all_folders);
1030 g_object_unref (G_OBJECT (folder));
1033 tny_iterator_next (iter);
1035 g_object_unref (G_OBJECT (iter));
1036 g_object_unref (G_OBJECT (folders));
1040 * Issues the "progress-changed" signal. The timer won't be removed,
1041 * so you must call g_source_remove to stop the signal emission
1044 idle_notify_progress (gpointer data)
1046 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1047 ModestMailOperationState *state;
1049 state = modest_mail_operation_clone_state (mail_op);
1051 /* This is a GDK lock because we are an idle callback and
1052 * the handlers of this signal can contain Gtk+ code */
1054 gdk_threads_enter (); /* CHECKED */
1055 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1056 gdk_threads_leave (); /* CHECKED */
1058 g_slice_free (ModestMailOperationState, state);
1064 * Issues the "progress-changed" signal and removes the timer. It uses
1065 * a lock to ensure that the progress information of the mail
1066 * operation is not modified while there are notifications pending
1069 idle_notify_progress_once (gpointer data)
1073 pair = (ModestPair *) data;
1075 /* This is a GDK lock because we are an idle callback and
1076 * the handlers of this signal can contain Gtk+ code */
1078 gdk_threads_enter (); /* CHECKED */
1079 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1080 gdk_threads_leave (); /* CHECKED */
1082 /* Free the state and the reference to the mail operation */
1083 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1084 g_object_unref (pair->first);
1090 * Used to notify the queue from the main
1091 * loop. We call it inside an idle call to achieve that
1094 idle_notify_queue (gpointer data)
1096 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1098 /* Do not need to block, the notify end will do it for us */
1099 modest_mail_operation_notify_end (mail_op);
1100 g_object_unref (mail_op);
1106 compare_headers_by_date (gconstpointer a,
1109 TnyHeader **header1, **header2;
1110 time_t sent1, sent2;
1112 header1 = (TnyHeader **) a;
1113 header2 = (TnyHeader **) b;
1115 sent1 = tny_header_get_date_sent (*header1);
1116 sent2 = tny_header_get_date_sent (*header2);
1118 /* We want the most recent ones (greater time_t) at the
1127 set_last_updated_idle (gpointer data)
1130 /* This is a GDK lock because we are an idle callback and
1131 * modest_account_mgr_set_int can contain Gtk+ code */
1133 gdk_threads_enter (); /* CHECKED - please recheck */
1135 /* It does not matter if the time is not exactly the same than
1136 the time when this idle was called, it's just an
1137 approximation and it won't be very different */
1139 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1141 MODEST_ACCOUNT_LAST_UPDATED,
1145 gdk_threads_leave (); /* CHECKED - please recheck */
1151 idle_update_account_cb (gpointer data)
1153 UpdateAccountInfo *idle_info;
1155 idle_info = (UpdateAccountInfo *) data;
1157 /* This is a GDK lock because we are an idle callback and
1158 * idle_info->callback can contain Gtk+ code */
1160 gdk_threads_enter (); /* CHECKED */
1161 idle_info->callback (idle_info->mail_op,
1162 idle_info->new_headers,
1163 idle_info->user_data);
1164 gdk_threads_leave (); /* CHECKED */
1167 g_object_unref (idle_info->mail_op);
1175 update_account_thread (gpointer thr_user_data)
1177 static gboolean first_time = TRUE;
1178 UpdateAccountInfo *info = NULL;
1179 TnyList *all_folders = NULL;
1180 GPtrArray *new_headers = NULL;
1181 TnyIterator *iter = NULL;
1182 TnyFolderStoreQuery *query = NULL;
1183 ModestMailOperationPrivate *priv = NULL;
1184 ModestTnySendQueue *send_queue = NULL;
1185 gint num_new_headers = 0;
1187 info = (UpdateAccountInfo *) thr_user_data;
1188 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1190 /* Get account and set it into mail_operation */
1191 priv->account = g_object_ref (info->account);
1194 * Previousl, we did this for POP3, to do a logout-login upon send/receive,
1195 * because many POP-servers (like Gmail) do not
1196 * show any updates unless we do that.
1197 * But that didn't work with gmail anyway,
1198 * and tinymail now takes care of this itself by disconnecting
1199 * automatically after using the connection.
1202 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT (priv->account))
1203 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1206 /* Get all the folders. We can do it synchronously because
1207 we're already running in a different thread than the UI */
1208 all_folders = tny_simple_list_new ();
1209 query = tny_folder_store_query_new ();
1210 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1211 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1216 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1220 iter = tny_list_create_iterator (all_folders);
1221 while (!tny_iterator_is_done (iter)) {
1222 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1224 recurse_folders (folder, query, all_folders);
1225 g_object_unref (folder);
1227 tny_iterator_next (iter);
1229 g_object_unref (G_OBJECT (iter));
1231 /* Update status and notify. We need to call the notification
1232 with a source function in order to call it from the main
1233 loop. We need that in order not to get into trouble with
1234 Gtk+. We use a timeout in order to provide more status
1235 information, because the sync tinymail call does not
1236 provide it for the moment */
1237 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1239 /* Refresh folders */
1240 num_new_headers = 0;
1241 new_headers = g_ptr_array_new ();
1242 iter = tny_list_create_iterator (all_folders);
1244 while (!tny_iterator_is_done (iter) && !priv->error &&
1245 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1247 InternalFolderObserver *observer;
1248 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1250 /* Refresh the folder */
1251 /* Our observer receives notification of new emails during folder refreshes,
1252 * so we can use observer->new_headers.
1254 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1255 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1257 /* This gets the status information (headers) from the server.
1258 * We use the blocking version, because we are already in a separate
1262 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1263 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1266 /* If the retrieve type is full messages, refresh and get the messages */
1267 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1269 iter = tny_list_create_iterator (observer->new_headers);
1270 while (!tny_iterator_is_done (iter)) {
1271 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1273 /* Apply per-message size limits */
1274 if (tny_header_get_message_size (header) < info->max_size)
1275 g_ptr_array_add (new_headers, g_object_ref (header));
1277 g_object_unref (header);
1278 tny_iterator_next (iter);
1280 g_object_unref (iter);
1282 /* We do not need to do it the first time
1283 because it's automatically done by the tree
1285 if (G_UNLIKELY (!first_time))
1286 tny_folder_poke_status (TNY_FOLDER (folder));
1288 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1289 g_object_unref (observer);
1293 g_object_unref (G_OBJECT (folder));
1296 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1298 tny_iterator_next (iter);
1301 g_object_unref (G_OBJECT (iter));
1302 g_source_remove (timeout);
1304 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1305 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1306 new_headers->len > 0) {
1310 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1312 /* Apply message count limit */
1313 /* If the number of messages exceeds the maximum, ask the
1314 * user to download them all,
1315 * as per the UI spec "Retrieval Limits" section in 4.4:
1317 if (new_headers->len > info->retrieve_limit) {
1318 /* TODO: Ask the user, instead of just
1320 * mail_nc_msg_count_limit_exceeded, with 'Get
1321 * all' and 'Newest only' buttons. */
1322 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1323 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1324 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1325 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1326 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1331 priv->total = MIN (new_headers->len, info->retrieve_limit);
1332 while (msg_num < priv->total) {
1334 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1335 TnyFolder *folder = tny_header_get_folder (header);
1336 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1337 ModestMailOperationState *state;
1341 /* We can not just use the mail operation because the
1342 values of done and total could change before the
1344 state = modest_mail_operation_clone_state (info->mail_op);
1345 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1346 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1347 pair, (GDestroyNotify) modest_pair_free);
1349 g_object_unref (msg);
1350 g_object_unref (folder);
1356 /* Get the number of new headers and free them */
1357 num_new_headers = new_headers->len;
1358 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1359 g_ptr_array_free (new_headers, FALSE);
1361 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1364 /* Perform send (if operation was not cancelled) */
1367 if (priv->account != NULL)
1368 g_object_unref (priv->account);
1369 priv->account = g_object_ref (info->transport_account);
1371 send_queue = modest_runtime_get_send_queue (info->transport_account);
1373 modest_tny_send_queue_try_to_send (send_queue);
1375 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1376 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1377 "cannot create a send queue for %s\n",
1378 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1379 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1382 /* Check if the operation was a success */
1384 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1386 /* Update the last updated key */
1387 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1388 set_last_updated_idle,
1389 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1390 (GDestroyNotify) g_free);
1395 if (info->callback) {
1396 UpdateAccountInfo *idle_info;
1398 /* This thread is not in the main lock */
1399 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1400 idle_info->mail_op = g_object_ref (info->mail_op);
1401 idle_info->new_headers = num_new_headers;
1402 idle_info->callback = info->callback;
1403 g_idle_add (idle_update_account_cb, idle_info);
1406 /* Notify about operation end. Note that the info could be
1407 freed before this idle happens, but the mail operation will
1409 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1412 g_object_unref (query);
1413 g_object_unref (all_folders);
1414 g_object_unref (info->account);
1415 g_object_unref (info->transport_account);
1416 g_free (info->retrieve_type);
1417 g_slice_free (UpdateAccountInfo, info);
1425 modest_mail_operation_update_account (ModestMailOperation *self,
1426 const gchar *account_name,
1427 UpdateAccountCallback callback,
1430 GThread *thread = NULL;
1431 UpdateAccountInfo *info = NULL;
1432 ModestMailOperationPrivate *priv = NULL;
1433 ModestAccountMgr *mgr = NULL;
1434 TnyStoreAccount *store_account = NULL;
1435 TnyTransportAccount *transport_account = NULL;
1437 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1438 g_return_val_if_fail (account_name, FALSE);
1440 /* Init mail operation. Set total and done to 0, and do not
1441 update them, this way the progress objects will know that
1442 we have no clue about the number of the objects */
1443 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1446 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1448 /* Get the Modest account */
1449 store_account = (TnyStoreAccount *)
1450 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1452 TNY_ACCOUNT_TYPE_STORE);
1454 /* Make sure that we have a connection, and request one
1456 * TODO: Is there some way to trigger this for every attempt to
1457 * use the network? */
1458 if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
1461 if (!store_account) {
1462 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1463 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1464 "cannot get tny store account for %s\n", account_name);
1469 /* Get the transport account, we can not do it in the thread
1470 due to some problems with dbus */
1471 transport_account = (TnyTransportAccount *)
1472 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1474 if (!transport_account) {
1475 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1476 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1477 "cannot get tny transport account for %s\n", account_name);
1481 /* Create the helper object */
1482 info = g_slice_new (UpdateAccountInfo);
1483 info->mail_op = self;
1484 info->account = store_account;
1485 info->transport_account = transport_account;
1486 info->callback = callback;
1487 info->user_data = user_data;
1489 /* Get the message size limit */
1490 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1491 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1492 if (info->max_size == 0)
1493 info->max_size = G_MAXINT;
1495 info->max_size = info->max_size * KB;
1497 /* Get per-account retrieval type */
1498 mgr = modest_runtime_get_account_mgr ();
1499 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1500 MODEST_ACCOUNT_RETRIEVE, FALSE);
1502 /* Get per-account message amount retrieval limit */
1503 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1504 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1505 if (info->retrieve_limit == 0)
1506 info->retrieve_limit = G_MAXINT;
1508 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1510 /* Set account busy */
1511 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1512 priv->account_name = g_strdup(account_name);
1514 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1519 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1521 callback (self, 0, user_data);
1522 modest_mail_operation_notify_end (self);
1526 /* ******************************************************************* */
1527 /* ************************** STORE ACTIONS ************************* */
1528 /* ******************************************************************* */
1532 modest_mail_operation_create_folder (ModestMailOperation *self,
1533 TnyFolderStore *parent,
1536 ModestMailOperationPrivate *priv;
1537 TnyFolder *new_folder = NULL;
1539 TnyList *list = tny_simple_list_new ();
1540 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1542 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1543 g_return_val_if_fail (name, NULL);
1545 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1547 /* Check for already existing folder */
1548 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1549 tny_folder_store_get_folders (parent, list, query, NULL);
1550 g_object_unref (G_OBJECT (query));
1552 if (tny_list_get_length (list) > 0) {
1553 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1554 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1555 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1556 _CS("ckdg_ib_folder_already_exists"));
1559 g_object_unref (G_OBJECT (list));
1562 if (TNY_IS_FOLDER (parent)) {
1563 /* Check folder rules */
1564 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1565 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1566 /* Set status failed and set an error */
1567 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1568 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1569 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1570 _("mail_in_ui_folder_create_error"));
1574 if (!strcmp (name, " ") || strchr (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_RULES,
1578 _("mail_in_ui_folder_create_error"));
1582 /* Create the folder */
1583 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1584 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1586 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1589 /* Notify about operation end */
1590 modest_mail_operation_notify_end (self);
1596 modest_mail_operation_remove_folder (ModestMailOperation *self,
1598 gboolean remove_to_trash)
1600 TnyAccount *account;
1601 ModestMailOperationPrivate *priv;
1602 ModestTnyFolderRules rules;
1604 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1605 g_return_if_fail (TNY_IS_FOLDER (folder));
1607 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1609 /* Check folder rules */
1610 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1611 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1612 /* Set status failed and set an error */
1613 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1614 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1615 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1616 _("mail_in_ui_folder_delete_error"));
1620 /* Get the account */
1621 account = modest_tny_folder_get_account (folder);
1622 priv->account = g_object_ref(account);
1624 /* Delete folder or move to trash */
1625 if (remove_to_trash) {
1626 TnyFolder *trash_folder = NULL;
1627 trash_folder = modest_tny_account_get_special_folder (account,
1628 TNY_FOLDER_TYPE_TRASH);
1629 /* TODO: error_handling */
1631 modest_mail_operation_xfer_folder (self, folder,
1632 TNY_FOLDER_STORE (trash_folder),
1634 g_object_unref (trash_folder);
1637 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1639 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1640 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1643 g_object_unref (G_OBJECT (parent));
1645 g_object_unref (G_OBJECT (account));
1648 /* Notify about operation end */
1649 modest_mail_operation_notify_end (self);
1653 transfer_folder_status_cb (GObject *obj,
1657 ModestMailOperation *self;
1658 ModestMailOperationPrivate *priv;
1659 ModestMailOperationState *state;
1660 XFerMsgAsyncHelper *helper;
1662 g_return_if_fail (status != NULL);
1663 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1665 helper = (XFerMsgAsyncHelper *) user_data;
1666 g_return_if_fail (helper != NULL);
1668 self = helper->mail_op;
1669 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1671 priv->done = status->position;
1672 priv->total = status->of_total;
1674 state = modest_mail_operation_clone_state (self);
1676 /* This is not a GDK lock because we are a Tinymail callback
1677 * which is already GDK locked by Tinymail */
1679 /* no gdk_threads_enter (), CHECKED */
1683 * Javier: if I remove this one, tny_folder_copy_async does not hang anymore
1685 * g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1687 * https://projects.maemo.org/bugzilla/show_bug.cgi?id=63060
1691 /* no gdk_threads_leave (), CHECKED */
1693 g_slice_free (ModestMailOperationState, state);
1698 transfer_folder_cb (TnyFolder *folder, gboolean cancelled,
1699 TnyFolderStore *into,
1700 TnyFolder *new_folder,
1704 XFerMsgAsyncHelper *helper;
1705 ModestMailOperation *self = NULL;
1706 ModestMailOperationPrivate *priv = NULL;
1708 helper = (XFerMsgAsyncHelper *) user_data;
1709 g_return_if_fail (helper != NULL);
1711 self = helper->mail_op;
1712 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1715 priv->error = g_error_copy (err);
1717 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1718 } else if (cancelled) {
1719 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1720 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1721 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1722 _("Transference of %s was cancelled."),
1723 tny_folder_get_name (folder));
1726 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1729 /* Notify about operation end */
1730 modest_mail_operation_notify_end (self);
1732 /* If user defined callback function was defined, call it */
1733 if (helper->user_callback) {
1735 /* This is not a GDK lock because we are a Tinymail callback
1736 * which is already GDK locked by Tinymail */
1738 /* no gdk_threads_enter (), CHECKED */
1739 helper->user_callback (priv->source, helper->user_data);
1740 /* no gdk_threads_leave () , CHECKED */
1744 g_object_unref (helper->mail_op);
1745 g_slice_free (XFerMsgAsyncHelper, helper);
1750 * This function checks if the new name is a valid name for our local
1751 * folders account. The new name could not be the same than then name
1752 * of any of the mandatory local folders
1754 * We can not rely on tinymail because tinymail does not check the
1755 * name of the virtual folders that the account could have in the case
1756 * that we're doing a rename (because it directly calls Camel which
1757 * knows nothing about our virtual folders).
1759 * In the case of an actual copy/move (i.e. move/copy a folder between
1760 * accounts) tinymail uses the tny_folder_store_create_account which
1761 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1762 * checks the new name of the folder, so this call in that case
1763 * wouldn't be needed. *But* NOTE that if tinymail changes its
1764 * implementation (if folder transfers within the same account is no
1765 * longer implemented as a rename) this call will allow Modest to work
1768 * If the new name is not valid, this function will set the status to
1769 * failed and will set also an error in the mail operation
1772 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1773 TnyFolderStore *into,
1774 const gchar *new_name)
1776 if (TNY_IS_ACCOUNT (into) &&
1777 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1778 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1780 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1781 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1782 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1783 _("FIXME: folder name already in use"));
1790 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1792 TnyFolderStore *parent,
1793 gboolean delete_original,
1794 XferMsgsAsynUserCallback user_callback,
1797 ModestMailOperationPrivate *priv = NULL;
1798 ModestTnyFolderRules parent_rules = 0, rules;
1799 XFerMsgAsyncHelper *helper = NULL;
1801 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1802 g_return_if_fail (TNY_IS_FOLDER (folder));
1804 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1806 /* Get account and set it into mail_operation */
1807 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1808 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1810 /* Get folder rules */
1811 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1812 if (TNY_IS_FOLDER (parent))
1813 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1815 /* The moveable restriction is applied also to copy operation */
1816 if ((gpointer) parent == (gpointer) folder ||
1817 (!TNY_IS_FOLDER_STORE (parent)) ||
1818 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1819 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1820 /* Set status failed and set an error */
1821 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1822 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1823 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1824 _("mail_in_ui_folder_move_target_error"));
1826 /* Notify the queue */
1827 modest_mail_operation_notify_end (self);
1828 } else if (TNY_IS_FOLDER (parent) &&
1829 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1830 /* Set status failed and set an error */
1831 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1832 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1833 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1834 _("FIXME: parent folder does not accept new folders"));
1836 /* Notify the queue */
1837 modest_mail_operation_notify_end (self);
1841 /* Check that the new folder name is not used by any
1842 special local folder */
1843 if (new_name_valid_if_local_account (priv, parent,
1844 tny_folder_get_name (folder))) {
1845 /* Create the helper */
1846 helper = g_slice_new0 (XFerMsgAsyncHelper);
1847 helper->mail_op = g_object_ref(self);
1848 helper->dest_folder = NULL;
1849 helper->headers = NULL;
1850 helper->user_callback = user_callback;
1851 helper->user_data = user_data;
1853 /* Move/Copy folder */
1854 tny_folder_copy_async (folder,
1856 tny_folder_get_name (folder),
1859 transfer_folder_status_cb,
1862 modest_mail_operation_notify_end (self);
1868 modest_mail_operation_rename_folder (ModestMailOperation *self,
1872 ModestMailOperationPrivate *priv;
1873 ModestTnyFolderRules rules;
1874 XFerMsgAsyncHelper *helper;
1876 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1877 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1878 g_return_if_fail (name);
1880 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1882 /* Get account and set it into mail_operation */
1883 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1885 /* Check folder rules */
1886 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1887 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1888 /* Set status failed and set an error */
1889 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1890 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1891 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1892 _("FIXME: unable to rename"));
1894 /* Notify about operation end */
1895 modest_mail_operation_notify_end (self);
1896 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1897 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1898 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1899 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1900 _("FIXME: unable to rename"));
1901 /* Notify about operation end */
1902 modest_mail_operation_notify_end (self);
1904 TnyFolderStore *into;
1906 into = tny_folder_get_folder_store (folder);
1908 /* Check that the new folder name is not used by any
1909 special local folder */
1910 if (new_name_valid_if_local_account (priv, into, name)) {
1911 /* Create the helper */
1912 helper = g_slice_new0 (XFerMsgAsyncHelper);
1913 helper->mail_op = g_object_ref(self);
1914 helper->dest_folder = NULL;
1915 helper->headers = NULL;
1916 helper->user_callback = NULL;
1917 helper->user_data = NULL;
1919 /* Rename. Camel handles folder subscription/unsubscription */
1920 tny_folder_copy_async (folder, into, name, TRUE,
1922 transfer_folder_status_cb,
1925 modest_mail_operation_notify_end (self);
1927 g_object_unref (into);
1931 /* ******************************************************************* */
1932 /* ************************** MSG ACTIONS ************************* */
1933 /* ******************************************************************* */
1935 void modest_mail_operation_get_msg (ModestMailOperation *self,
1937 GetMsgAsyncUserCallback user_callback,
1940 GetMsgAsyncHelper *helper = NULL;
1942 ModestMailOperationPrivate *priv;
1944 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1945 g_return_if_fail (TNY_IS_HEADER (header));
1947 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1948 folder = tny_header_get_folder (header);
1950 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1952 /* Get message from folder */
1954 /* Get account and set it into mail_operation */
1955 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1957 /* Check for cached messages */
1958 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
1959 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1961 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1963 helper = g_slice_new0 (GetMsgAsyncHelper);
1964 helper->mail_op = self;
1965 helper->user_callback = user_callback;
1966 helper->user_data = user_data;
1967 helper->header = g_object_ref (header);
1969 // The callback's reference so that the mail op is not
1970 // finalized until the async operation is completed even if
1971 // the user canceled the request meanwhile.
1972 g_object_ref (G_OBJECT (helper->mail_op));
1974 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1976 g_object_unref (G_OBJECT (folder));
1978 /* Set status failed and set an error */
1979 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1980 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1981 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1982 _("Error trying to get a message. No folder found for header"));
1984 /* Notify the queue */
1985 modest_mail_operation_notify_end (self);
1990 get_msg_cb (TnyFolder *folder,
1996 GetMsgAsyncHelper *helper = NULL;
1997 ModestMailOperation *self = NULL;
1998 ModestMailOperationPrivate *priv = NULL;
2000 helper = (GetMsgAsyncHelper *) user_data;
2001 g_return_if_fail (helper != NULL);
2002 self = helper->mail_op;
2003 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2004 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2006 /* Check errors and cancel */
2008 priv->error = g_error_copy (error);
2009 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2010 } else if (cancelled) {
2011 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2012 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2013 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2014 _("Error trying to refresh the contents of %s"),
2015 tny_folder_get_name (folder));
2017 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2020 /* If user defined callback function was defined, call it even
2021 if the operation failed*/
2022 if (helper->user_callback) {
2023 /* This is not a GDK lock because we are a Tinymail callback
2024 * which is already GDK locked by Tinymail */
2026 /* no gdk_threads_enter (), CHECKED */
2027 helper->user_callback (self, helper->header, msg, helper->user_data);
2028 /* no gdk_threads_leave (), CHECKED */
2031 /* Notify about operation end */
2032 modest_mail_operation_notify_end (self);
2034 g_object_unref (helper->mail_op);
2035 g_object_unref (helper->header);
2036 g_slice_free (GetMsgAsyncHelper, helper);
2041 get_msg_status_cb (GObject *obj,
2045 GetMsgAsyncHelper *helper = NULL;
2046 ModestMailOperation *self;
2047 ModestMailOperationPrivate *priv;
2048 ModestMailOperationState *state;
2050 g_return_if_fail (status != NULL);
2051 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2053 helper = (GetMsgAsyncHelper *) user_data;
2054 g_return_if_fail (helper != NULL);
2056 self = helper->mail_op;
2057 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2062 state = modest_mail_operation_clone_state (self);
2063 state->bytes_done = status->position;
2064 state->bytes_total = status->of_total;
2066 /* This is not a GDK lock because we are a Tinymail callback
2067 * which is already GDK locked by Tinymail */
2069 /* no gdk_threads_enter (), CHECKED */
2070 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2071 /* no gdk_threads_leave (), CHECKED */
2073 g_slice_free (ModestMailOperationState, state);
2076 /****************************************************/
2078 ModestMailOperation *mail_op;
2080 GetMsgAsyncUserCallback user_callback;
2082 GDestroyNotify notify;
2086 GetMsgAsyncUserCallback user_callback;
2090 ModestMailOperation *mail_op;
2091 } NotifyGetMsgsInfo;
2095 * Used by get_msgs_full_thread to call the user_callback for each
2096 * message that has been read
2099 notify_get_msgs_full (gpointer data)
2101 NotifyGetMsgsInfo *info;
2103 info = (NotifyGetMsgsInfo *) data;
2105 /* This is a GDK lock because we are an idle callback and
2106 * because info->user_callback can contain Gtk+ code */
2108 gdk_threads_enter (); /* CHECKED */
2109 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2110 gdk_threads_leave (); /* CHECKED */
2112 g_slice_free (NotifyGetMsgsInfo, info);
2118 * Used by get_msgs_full_thread to free al the thread resources and to
2119 * call the destroy function for the passed user_data
2122 get_msgs_full_destroyer (gpointer data)
2124 GetFullMsgsInfo *info;
2126 info = (GetFullMsgsInfo *) data;
2130 /* This is a GDK lock because we are an idle callback and
2131 * because info->notify can contain Gtk+ code */
2133 gdk_threads_enter (); /* CHECKED */
2134 info->notify (info->user_data);
2135 gdk_threads_leave (); /* CHECKED */
2139 g_object_unref (info->headers);
2140 g_slice_free (GetFullMsgsInfo, info);
2146 get_msgs_full_thread (gpointer thr_user_data)
2148 GetFullMsgsInfo *info;
2149 ModestMailOperationPrivate *priv = NULL;
2150 TnyIterator *iter = NULL;
2152 info = (GetFullMsgsInfo *) thr_user_data;
2153 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2155 iter = tny_list_create_iterator (info->headers);
2156 while (!tny_iterator_is_done (iter)) {
2160 header = TNY_HEADER (tny_iterator_get_current (iter));
2161 folder = tny_header_get_folder (header);
2163 /* Check for cached messages */
2164 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2165 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2167 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2169 /* Get message from folder */
2172 /* The callback will call it per each header */
2173 msg = tny_folder_get_msg (folder, header, &(priv->error));
2176 ModestMailOperationState *state;
2181 /* notify progress */
2182 state = modest_mail_operation_clone_state (info->mail_op);
2183 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2184 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2185 pair, (GDestroyNotify) modest_pair_free);
2187 /* The callback is the responsible for
2188 freeing the message */
2189 if (info->user_callback) {
2190 NotifyGetMsgsInfo *info_notify;
2191 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2192 info_notify->user_callback = info->user_callback;
2193 info_notify->mail_op = info->mail_op;
2194 info_notify->header = g_object_ref (header);
2195 info_notify->msg = g_object_ref (msg);
2196 info_notify->user_data = info->user_data;
2197 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2198 notify_get_msgs_full,
2201 g_object_unref (msg);
2204 /* Set status failed and set an error */
2205 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2206 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2207 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2208 "Error trying to get a message. No folder found for header");
2212 g_object_unref (header);
2214 tny_iterator_next (iter);
2217 /* Set operation status */
2218 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2219 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2221 /* Notify about operation end */
2222 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2224 /* Free thread resources. Will be called after all previous idles */
2225 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2231 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2232 TnyList *header_list,
2233 GetMsgAsyncUserCallback user_callback,
2235 GDestroyNotify notify)
2237 TnyHeader *header = NULL;
2238 TnyFolder *folder = NULL;
2240 ModestMailOperationPrivate *priv = NULL;
2241 GetFullMsgsInfo *info = NULL;
2242 gboolean size_ok = TRUE;
2244 TnyIterator *iter = NULL;
2246 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2248 /* Init mail operation */
2249 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2250 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2252 priv->total = tny_list_get_length(header_list);
2254 /* Get account and set it into mail_operation */
2255 if (tny_list_get_length (header_list) >= 1) {
2256 iter = tny_list_create_iterator (header_list);
2257 header = TNY_HEADER (tny_iterator_get_current (iter));
2259 folder = tny_header_get_folder (header);
2261 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2263 g_object_unref (folder);
2266 g_object_unref (header);
2269 if (tny_list_get_length (header_list) == 1) {
2270 g_object_unref (iter);
2275 /* Get msg size limit */
2276 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2277 MODEST_CONF_MSG_SIZE_LIMIT,
2280 g_clear_error (&(priv->error));
2281 max_size = G_MAXINT;
2283 max_size = max_size * KB;
2286 /* Check message size limits. If there is only one message
2287 always retrieve it */
2289 while (!tny_iterator_is_done (iter) && size_ok) {
2290 header = TNY_HEADER (tny_iterator_get_current (iter));
2292 if (tny_header_get_message_size (header) >= max_size)
2294 g_object_unref (header);
2297 tny_iterator_next (iter);
2299 g_object_unref (iter);
2303 /* Create the info */
2304 info = g_slice_new0 (GetFullMsgsInfo);
2305 info->mail_op = self;
2306 info->user_callback = user_callback;
2307 info->user_data = user_data;
2308 info->headers = g_object_ref (header_list);
2309 info->notify = notify;
2311 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2313 /* Set status failed and set an error */
2314 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2315 /* FIXME: the error msg is different for pop */
2316 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2317 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2318 _("emev_ni_ui_imap_msg_size_exceed_error"));
2319 /* Remove from queue and free resources */
2320 modest_mail_operation_notify_end (self);
2328 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2329 gboolean remove_to_trash /*ignored*/)
2332 ModestMailOperationPrivate *priv;
2334 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2335 g_return_if_fail (TNY_IS_HEADER (header));
2337 if (remove_to_trash)
2338 g_warning ("remove to trash is not implemented");
2340 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2341 folder = tny_header_get_folder (header);
2343 /* Get account and set it into mail_operation */
2344 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2346 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2348 /* remove message from folder */
2349 tny_folder_remove_msg (folder, header, &(priv->error));
2350 /* if (!priv->error) { */
2351 /* tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED); */
2352 /* tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN); */
2354 /* if (TNY_IS_CAMEL_IMAP_FOLDER (folder)) */
2355 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* FALSE --> don't expunge *\/ */
2356 /* /\* tny_folder_sync (folder, FALSE, &(priv->error)); /\\* FALSE --> don't expunge *\\/ *\/ */
2357 /* else if (TNY_IS_CAMEL_POP_FOLDER (folder)) */
2358 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* TRUE --> dont expunge *\/ */
2359 /* /\* tny_folder_sync (folder, TRUE, &(priv->error)); /\\* TRUE --> expunge *\\/ *\/ */
2361 /* /\* local folders *\/ */
2362 /* tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /\* TRUE --> expunge *\/ */
2363 /* /\* tny_folder_sync (folder, TRUE, &(priv->error)); /\\* TRUE --> expunge *\\/ *\/ */
2369 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2371 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2374 g_object_unref (G_OBJECT (folder));
2376 /* Notify about operation end */
2377 modest_mail_operation_notify_end (self);
2381 transfer_msgs_status_cb (GObject *obj,
2385 XFerMsgAsyncHelper *helper = NULL;
2386 ModestMailOperation *self;
2387 ModestMailOperationPrivate *priv;
2388 ModestMailOperationState *state;
2391 g_return_if_fail (status != NULL);
2392 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2394 helper = (XFerMsgAsyncHelper *) user_data;
2395 g_return_if_fail (helper != NULL);
2397 self = helper->mail_op;
2398 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2400 priv->done = status->position;
2401 priv->total = status->of_total;
2403 state = modest_mail_operation_clone_state (self);
2405 /* This is not a GDK lock because we are a Tinymail callback and
2406 * Tinymail already acquires the Gdk lock */
2408 /* no gdk_threads_enter (), CHECKED */
2410 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2412 /* no gdk_threads_leave (), CHECKED */
2414 g_slice_free (ModestMailOperationState, state);
2419 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2421 XFerMsgAsyncHelper *helper;
2422 ModestMailOperation *self;
2423 ModestMailOperationPrivate *priv;
2424 TnyIterator *iter = NULL;
2425 TnyHeader *header = NULL;
2427 helper = (XFerMsgAsyncHelper *) user_data;
2428 self = helper->mail_op;
2430 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2433 priv->error = g_error_copy (err);
2435 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2436 } else if (cancelled) {
2437 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2438 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2439 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2440 _("Error trying to refresh the contents of %s"),
2441 tny_folder_get_name (folder));
2444 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2448 /* Mark headers as deleted and seen */
2449 if ((helper->delete) &&
2450 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2451 iter = tny_list_create_iterator (helper->headers);
2452 while (!tny_iterator_is_done (iter)) {
2453 header = TNY_HEADER (tny_iterator_get_current (iter));
2454 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2455 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2456 g_object_unref (header);
2458 tny_iterator_next (iter);
2464 /* Notify about operation end */
2465 modest_mail_operation_notify_end (self);
2467 /* If user defined callback function was defined, call it */
2468 if (helper->user_callback) {
2469 /* This is not a GDK lock because we are a Tinymail callback and
2470 * Tinymail already acquires the Gdk lock */
2472 /* no gdk_threads_enter (), CHECKED */
2473 helper->user_callback (priv->source, helper->user_data);
2474 /* no gdk_threads_leave (), CHECKED */
2478 if (helper->headers)
2479 g_object_unref (helper->headers);
2480 if (helper->dest_folder)
2481 g_object_unref (helper->dest_folder);
2482 if (helper->mail_op)
2483 g_object_unref (helper->mail_op);
2485 g_object_unref (folder);
2487 g_object_unref (iter);
2488 g_slice_free (XFerMsgAsyncHelper, helper);
2493 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2496 gboolean delete_original,
2497 XferMsgsAsynUserCallback user_callback,
2500 ModestMailOperationPrivate *priv = NULL;
2501 TnyIterator *iter = NULL;
2502 TnyFolder *src_folder = NULL;
2503 XFerMsgAsyncHelper *helper = NULL;
2504 TnyHeader *header = NULL;
2505 ModestTnyFolderRules rules = 0;
2506 const gchar *id1 = NULL;
2507 const gchar *id2 = NULL;
2508 gboolean same_folder = FALSE;
2510 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2511 g_return_if_fail (TNY_IS_LIST (headers));
2512 g_return_if_fail (TNY_IS_FOLDER (folder));
2514 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2517 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2519 /* Apply folder rules */
2520 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2521 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2522 /* Set status failed and set an error */
2523 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2524 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2525 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2526 _CS("ckct_ib_unable_to_paste_here"));
2527 /* Notify the queue */
2528 modest_mail_operation_notify_end (self);
2532 /* Get source folder */
2533 iter = tny_list_create_iterator (headers);
2534 header = TNY_HEADER (tny_iterator_get_current (iter));
2536 src_folder = tny_header_get_folder (header);
2537 g_object_unref (header);
2540 g_object_unref (iter);
2542 /* Check folder source and destination */
2543 id1 = tny_folder_get_id (src_folder);
2544 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2545 same_folder = !g_ascii_strcasecmp (id1, id2);
2547 /* Set status failed and set an error */
2548 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2549 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2550 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2551 _("mcen_ib_unable_to_copy_samefolder"));
2553 /* Notify the queue */
2554 modest_mail_operation_notify_end (self);
2557 g_object_unref (src_folder);
2561 /* Create the helper */
2562 helper = g_slice_new0 (XFerMsgAsyncHelper);
2563 helper->mail_op = g_object_ref(self);
2564 helper->dest_folder = g_object_ref(folder);
2565 helper->headers = g_object_ref(headers);
2566 helper->user_callback = user_callback;
2567 helper->user_data = user_data;
2568 helper->delete = delete_original;
2570 /* Get account and set it into mail_operation */
2571 priv->account = modest_tny_folder_get_account (src_folder);
2573 /* Transfer messages */
2574 tny_folder_transfer_msgs_async (src_folder,
2579 transfer_msgs_status_cb,
2585 on_refresh_folder (TnyFolder *folder,
2590 RefreshAsyncHelper *helper = NULL;
2591 ModestMailOperation *self = NULL;
2592 ModestMailOperationPrivate *priv = NULL;
2594 helper = (RefreshAsyncHelper *) user_data;
2595 self = helper->mail_op;
2596 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2598 g_return_if_fail(priv!=NULL);
2601 priv->error = g_error_copy (error);
2602 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2603 printf("DEBUG: %s: Operation error:\n %s", __FUNCTION__,
2609 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2610 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2611 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2612 _("Error trying to refresh the contents of %s"),
2613 tny_folder_get_name (folder));
2614 printf("DEBUG: %s: Operation cancelled.\n", __FUNCTION__);
2618 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2620 /* Call user defined callback, if it exists */
2621 if (helper->user_callback) {
2623 /* This is not a GDK lock because we are a Tinymail callback and
2624 * Tinymail already acquires the Gdk lock */
2626 /* no gdk_threads_enter (), CHECKED */
2627 helper->user_callback (self, folder, helper->user_data);
2628 /* no gdk_threads_leave (), CHECKED */
2633 g_slice_free (RefreshAsyncHelper, helper);
2635 /* Notify about operation end */
2636 modest_mail_operation_notify_end (self);
2637 g_object_unref(self);
2641 on_refresh_folder_status_update (GObject *obj,
2645 RefreshAsyncHelper *helper = NULL;
2646 ModestMailOperation *self = NULL;
2647 ModestMailOperationPrivate *priv = NULL;
2648 ModestMailOperationState *state;
2650 g_return_if_fail (user_data != NULL);
2651 g_return_if_fail (status != NULL);
2652 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2654 helper = (RefreshAsyncHelper *) user_data;
2655 self = helper->mail_op;
2656 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2658 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2660 priv->done = status->position;
2661 priv->total = status->of_total;
2663 state = modest_mail_operation_clone_state (self);
2665 /* This is not a GDK lock because we are a Tinymail callback and
2666 * Tinymail already acquires the Gdk lock */
2668 /* no gdk_threads_enter (), CHECKED */
2670 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2672 /* no gdk_threads_leave (), CHECKED */
2674 g_slice_free (ModestMailOperationState, state);
2678 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2680 RefreshAsyncUserCallback user_callback,
2683 ModestMailOperationPrivate *priv = NULL;
2684 RefreshAsyncHelper *helper = NULL;
2686 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2688 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2690 /* Get account and set it into mail_operation */
2691 priv->account = modest_tny_folder_get_account (folder);
2693 /* Create the helper */
2694 helper = g_slice_new0 (RefreshAsyncHelper);
2695 helper->mail_op = g_object_ref(self);
2696 helper->user_callback = user_callback;
2697 helper->user_data = user_data;
2699 /* Refresh the folder. TODO: tinymail could issue a status
2700 updates before the callback call then this could happen. We
2701 must review the design */
2702 tny_folder_refresh_async (folder,
2704 on_refresh_folder_status_update,
2710 * It's used by the mail operation queue to notify the observers
2711 * attached to that signal that the operation finished. We need to use
2712 * that because tinymail does not give us the progress of a given
2713 * operation when it finishes (it directly calls the operation
2717 modest_mail_operation_notify_end (ModestMailOperation *self)
2719 ModestMailOperationState *state;
2720 ModestMailOperationPrivate *priv = NULL;
2722 g_return_if_fail (self);
2724 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2726 /* Set the account back to not busy */
2727 if (priv->account_name) {
2728 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2729 priv->account_name, FALSE);
2730 g_free(priv->account_name);
2731 priv->account_name = NULL;
2734 /* Notify the observers about the mail operation end */
2735 /* We do not wrapp this emission because we assume that this
2736 function is always called from within the main lock */
2737 state = modest_mail_operation_clone_state (self);
2738 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2739 g_slice_free (ModestMailOperationState, state);