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 gdk_threads_enter ();
579 info->callback (info->mail_op, info->msg, info->userdata);
580 gdk_threads_leave ();
581 g_object_unref (info->mail_op);
583 g_object_unref (info->msg);
584 g_slice_free (CreateMsgIdleInfo, info);
590 create_msg_thread (gpointer thread_data)
592 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
593 TnyMsg *new_msg = NULL;
594 ModestMailOperationPrivate *priv;
596 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
597 if (info->html_body == NULL) {
598 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
599 info->bcc, info->subject, info->plain_body,
600 info->attachments_list); /* FIXME: attachments */
602 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
603 info->bcc, info->subject, info->html_body,
604 info->plain_body, info->attachments_list);
609 /* Set priority flags in message */
610 header = tny_msg_get_header (new_msg);
611 if (info->priority_flags != 0)
612 tny_header_set_flags (header, info->priority_flags);
613 if (info->attachments_list != NULL) {
614 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
616 g_object_unref (G_OBJECT(header));
618 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
619 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
620 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
621 "modest: failed to create a new msg\n");
629 g_free (info->plain_body);
630 g_free (info->html_body);
631 g_free (info->subject);
632 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
633 g_list_free (info->attachments_list);
635 if (info->callback) {
636 CreateMsgIdleInfo *idle_info;
637 idle_info = g_slice_new0 (CreateMsgIdleInfo);
638 idle_info->mail_op = info->mail_op;
639 g_object_ref (info->mail_op);
640 idle_info->msg = new_msg;
642 g_object_ref (new_msg);
643 idle_info->callback = info->callback;
644 idle_info->userdata = info->userdata;
645 g_idle_add (idle_create_msg_cb, idle_info);
647 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
650 g_object_unref (info->mail_op);
651 g_slice_free (CreateMsgInfo, info);
656 modest_mail_operation_create_msg (ModestMailOperation *self,
657 const gchar *from, const gchar *to,
658 const gchar *cc, const gchar *bcc,
659 const gchar *subject, const gchar *plain_body,
660 const gchar *html_body,
661 const GList *attachments_list,
662 TnyHeaderFlags priority_flags,
663 ModestMailOperationCreateMsgCallback callback,
666 CreateMsgInfo *info = NULL;
668 info = g_slice_new0 (CreateMsgInfo);
669 info->mail_op = self;
672 info->from = g_strdup (from);
673 info->to = g_strdup (to);
674 info->cc = g_strdup (cc);
675 info->bcc = g_strdup (bcc);
676 info->subject = g_strdup (subject);
677 info->plain_body = g_strdup (plain_body);
678 info->html_body = g_strdup (html_body);
679 info->attachments_list = g_list_copy ((GList *) attachments_list);
680 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
681 info->priority_flags = priority_flags;
683 info->callback = callback;
684 info->userdata = userdata;
686 g_thread_create (create_msg_thread, info, FALSE, NULL);
691 TnyTransportAccount *transport_account;
696 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
700 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
701 TnyFolder *draft_folder = NULL;
702 TnyFolder *outbox_folder = NULL;
709 /* Call mail operation */
710 modest_mail_operation_send_mail (self, info->transport_account, msg);
712 /* Remove old mail from its source folder */
713 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
714 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_OUTBOX);
715 if (info->draft_msg != NULL) {
716 TnyFolder *folder = NULL;
717 TnyFolder *src_folder = NULL;
718 TnyFolderType folder_type;
719 folder = tny_msg_get_folder (info->draft_msg);
720 if (folder == NULL) goto end;
721 folder_type = modest_tny_folder_guess_folder_type (folder);
722 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
723 src_folder = outbox_folder;
725 src_folder = draft_folder;
727 /* Note: This can fail (with a warning) if the message is not really already in a folder,
728 * because this function requires it to have a UID. */
729 header = tny_msg_get_header (info->draft_msg);
730 tny_folder_remove_msg (src_folder, header, NULL);
731 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
732 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
733 g_object_unref (header);
734 g_object_unref (folder);
739 g_object_unref (info->draft_msg);
741 g_object_unref (draft_folder);
743 g_object_unref (outbox_folder);
744 if (info->transport_account)
745 g_object_unref (info->transport_account);
746 g_slice_free (SendNewMailInfo, info);
747 modest_mail_operation_notify_end (self);
751 modest_mail_operation_send_new_mail (ModestMailOperation *self,
752 TnyTransportAccount *transport_account,
754 const gchar *from, const gchar *to,
755 const gchar *cc, const gchar *bcc,
756 const gchar *subject, const gchar *plain_body,
757 const gchar *html_body,
758 const GList *attachments_list,
759 TnyHeaderFlags priority_flags)
761 ModestMailOperationPrivate *priv = NULL;
762 SendNewMailInfo *info;
764 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
765 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
767 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
769 /* Check parametters */
771 /* Set status failed and set an error */
772 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
773 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
774 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
775 _("Error trying to send a mail. You need to set at least one recipient"));
778 info = g_slice_new0 (SendNewMailInfo);
779 info->transport_account = transport_account;
780 if (transport_account)
781 g_object_ref (transport_account);
782 info->draft_msg = draft_msg;
784 g_object_ref (draft_msg);
785 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
786 attachments_list, priority_flags,
787 modest_mail_operation_send_new_mail_cb, info);
793 TnyTransportAccount *transport_account;
795 ModestMsgEditWindow *edit_window;
799 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
803 TnyFolder *src_folder = NULL;
804 TnyFolder *folder = NULL;
805 TnyHeader *header = NULL;
806 ModestMailOperationPrivate *priv = NULL;
807 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
809 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
811 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
812 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
813 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
814 "modest: failed to create a new msg\n");
818 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
820 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
821 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
822 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
823 "modest: failed to create a new msg\n");
828 tny_folder_add_msg (folder, msg, &(priv->error));
830 if ((!priv->error) && (info->draft_msg != NULL)) {
831 header = tny_msg_get_header (info->draft_msg);
832 src_folder = tny_header_get_folder (header);
833 /* Remove the old draft expunging it */
834 tny_folder_remove_msg (src_folder, header, NULL);
835 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
836 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
837 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */
838 g_object_unref (header);
842 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
844 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
846 if (info->edit_window)
847 modest_msg_edit_window_set_draft (info->edit_window, msg);
852 g_object_unref (G_OBJECT(folder));
854 g_object_unref (G_OBJECT(src_folder));
855 if (info->edit_window)
856 g_object_unref (G_OBJECT(info->edit_window));
858 g_object_unref (G_OBJECT (info->draft_msg));
859 if (info->transport_account)
860 g_object_unref (G_OBJECT(info->transport_account));
861 g_slice_free (SaveToDraftsInfo, info);
863 modest_mail_operation_notify_end (self);
867 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
868 TnyTransportAccount *transport_account,
870 ModestMsgEditWindow *edit_window,
871 const gchar *from, const gchar *to,
872 const gchar *cc, const gchar *bcc,
873 const gchar *subject, const gchar *plain_body,
874 const gchar *html_body,
875 const GList *attachments_list,
876 TnyHeaderFlags priority_flags)
878 ModestMailOperationPrivate *priv = NULL;
879 SaveToDraftsInfo *info = NULL;
881 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
882 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
884 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
886 /* Get account and set it into mail_operation */
887 priv->account = g_object_ref (transport_account);
889 info = g_slice_new0 (SaveToDraftsInfo);
890 info->transport_account = g_object_ref (transport_account);
891 info->draft_msg = draft_msg;
893 g_object_ref (draft_msg);
894 info->edit_window = edit_window;
896 g_object_ref (edit_window);
898 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
899 attachments_list, priority_flags,
900 modest_mail_operation_save_to_drafts_cb, info);
906 ModestMailOperation *mail_op;
907 TnyStoreAccount *account;
908 TnyTransportAccount *transport_account;
911 gchar *retrieve_type;
913 UpdateAccountCallback callback;
920 ModestMailOperation *mail_op;
921 TnyMimePart *mime_part;
923 GetMimePartSizeCallback callback;
925 } GetMimePartSizeInfo;
927 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
928 /* We use this folder observer to track the headers that have been
929 * added to a folder */
932 TnyList *new_headers;
933 } InternalFolderObserver;
937 } InternalFolderObserverClass;
939 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
941 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
942 internal_folder_observer,
944 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
948 foreach_add_item (gpointer header, gpointer user_data)
950 tny_list_prepend (TNY_LIST (user_data),
951 g_object_ref (G_OBJECT (header)));
954 /* This is the method that looks for new messages in a folder */
956 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
958 InternalFolderObserver *derived = (InternalFolderObserver *)self;
960 TnyFolderChangeChanged changed;
962 changed = tny_folder_change_get_changed (change);
964 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
967 /* Get added headers */
968 list = tny_simple_list_new ();
969 tny_folder_change_get_added_headers (change, list);
971 /* Add them to the folder observer */
972 tny_list_foreach (list, foreach_add_item,
973 derived->new_headers);
975 g_object_unref (G_OBJECT (list));
980 internal_folder_observer_init (InternalFolderObserver *self)
982 self->new_headers = tny_simple_list_new ();
985 internal_folder_observer_finalize (GObject *object)
987 InternalFolderObserver *self;
989 self = (InternalFolderObserver *) object;
990 g_object_unref (self->new_headers);
992 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
995 tny_folder_observer_init (TnyFolderObserverIface *iface)
997 iface->update_func = internal_folder_observer_update;
1000 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1002 GObjectClass *object_class;
1004 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1005 object_class = (GObjectClass*) klass;
1006 object_class->finalize = internal_folder_observer_finalize;
1012 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
1015 TnyList *folders = tny_simple_list_new ();
1017 tny_folder_store_get_folders (store, folders, query, NULL);
1018 iter = tny_list_create_iterator (folders);
1020 while (!tny_iterator_is_done (iter)) {
1022 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1024 tny_list_prepend (all_folders, G_OBJECT (folder));
1025 recurse_folders (folder, query, all_folders);
1026 g_object_unref (G_OBJECT (folder));
1029 tny_iterator_next (iter);
1031 g_object_unref (G_OBJECT (iter));
1032 g_object_unref (G_OBJECT (folders));
1036 * Issues the "progress-changed" signal. The timer won't be removed,
1037 * so you must call g_source_remove to stop the signal emission
1040 idle_notify_progress (gpointer data)
1042 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1043 ModestMailOperationState *state;
1045 state = modest_mail_operation_clone_state (mail_op);
1046 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1047 gdk_threads_enter ();
1049 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1050 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1051 gdk_threads_leave ();
1053 g_slice_free (ModestMailOperationState, state);
1059 * Issues the "progress-changed" signal and removes the timer. It uses
1060 * a lock to ensure that the progress information of the mail
1061 * operation is not modified while there are notifications pending
1064 idle_notify_progress_once (gpointer data)
1068 pair = (ModestPair *) data;
1070 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1071 gdk_threads_enter ();
1073 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1074 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1075 gdk_threads_leave ();
1078 /* Free the state and the reference to the mail operation */
1079 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1080 g_object_unref (pair->first);
1086 * Used to notify the queue from the main
1087 * loop. We call it inside an idle call to achieve that
1090 idle_notify_queue (gpointer data)
1092 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1094 /* Do not need to block, the notify end will do it for us */
1095 modest_mail_operation_notify_end (mail_op);
1096 g_object_unref (mail_op);
1102 compare_headers_by_date (gconstpointer a,
1105 TnyHeader **header1, **header2;
1106 time_t sent1, sent2;
1108 header1 = (TnyHeader **) a;
1109 header2 = (TnyHeader **) b;
1111 sent1 = tny_header_get_date_sent (*header1);
1112 sent2 = tny_header_get_date_sent (*header2);
1114 /* We want the most recent ones (greater time_t) at the
1123 set_last_updated_idle (gpointer data)
1125 gdk_threads_enter ();
1127 /* It does not matter if the time is not exactly the same than
1128 the time when this idle was called, it's just an
1129 approximation and it won't be very different */
1130 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1132 MODEST_ACCOUNT_LAST_UPDATED,
1136 gdk_threads_leave ();
1142 idle_update_account_cb (gpointer data)
1144 UpdateAccountInfo *idle_info;
1146 idle_info = (UpdateAccountInfo *) data;
1148 gdk_threads_enter ();
1149 idle_info->callback (idle_info->mail_op,
1150 idle_info->new_headers,
1151 idle_info->user_data);
1152 gdk_threads_leave ();
1155 g_object_unref (idle_info->mail_op);
1163 update_account_thread (gpointer thr_user_data)
1165 static gboolean first_time = TRUE;
1166 UpdateAccountInfo *info = NULL;
1167 TnyList *all_folders = NULL;
1168 GPtrArray *new_headers = NULL;
1169 TnyIterator *iter = NULL;
1170 TnyFolderStoreQuery *query = NULL;
1171 ModestMailOperationPrivate *priv = NULL;
1172 ModestTnySendQueue *send_queue = NULL;
1173 gint num_new_headers = 0;
1175 info = (UpdateAccountInfo *) thr_user_data;
1176 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1178 /* Get account and set it into mail_operation */
1179 priv->account = g_object_ref (info->account);
1182 * Previousl, we did this for POP3, to do a logout-login upon send/receive,
1183 * because many POP-servers (like Gmail) do not
1184 * show any updates unless we do that.
1185 * But that didn't work with gmail anyway,
1186 * and tinymail now takes care of this itself by disconnecting
1187 * automatically after using the connection.
1190 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT (priv->account))
1191 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1194 /* Get all the folders. We can do it synchronously because
1195 we're already running in a different thread than the UI */
1196 all_folders = tny_simple_list_new ();
1197 query = tny_folder_store_query_new ();
1198 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1199 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1204 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1208 iter = tny_list_create_iterator (all_folders);
1209 while (!tny_iterator_is_done (iter)) {
1210 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1212 recurse_folders (folder, query, all_folders);
1213 g_object_unref (folder);
1215 tny_iterator_next (iter);
1217 g_object_unref (G_OBJECT (iter));
1219 /* Update status and notify. We need to call the notification
1220 with a source function in order to call it from the main
1221 loop. We need that in order not to get into trouble with
1222 Gtk+. We use a timeout in order to provide more status
1223 information, because the sync tinymail call does not
1224 provide it for the moment */
1225 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1227 /* Refresh folders */
1228 num_new_headers = 0;
1229 new_headers = g_ptr_array_new ();
1230 iter = tny_list_create_iterator (all_folders);
1232 while (!tny_iterator_is_done (iter) && !priv->error &&
1233 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1235 InternalFolderObserver *observer;
1236 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1238 /* Refresh the folder */
1239 /* Our observer receives notification of new emails during folder refreshes,
1240 * so we can use observer->new_headers.
1242 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1243 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1245 /* This gets the status information (headers) from the server.
1246 * We use the blocking version, because we are already in a separate
1250 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1251 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1254 /* If the retrieve type is full messages, refresh and get the messages */
1255 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1257 iter = tny_list_create_iterator (observer->new_headers);
1258 while (!tny_iterator_is_done (iter)) {
1259 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1261 /* Apply per-message size limits */
1262 if (tny_header_get_message_size (header) < info->max_size)
1263 g_ptr_array_add (new_headers, g_object_ref (header));
1265 g_object_unref (header);
1266 tny_iterator_next (iter);
1268 g_object_unref (iter);
1270 /* We do not need to do it the first time
1271 because it's automatically done by the tree
1273 if (G_UNLIKELY (!first_time))
1274 tny_folder_poke_status (TNY_FOLDER (folder));
1276 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1277 g_object_unref (observer);
1281 g_object_unref (G_OBJECT (folder));
1284 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1286 tny_iterator_next (iter);
1289 g_object_unref (G_OBJECT (iter));
1290 g_source_remove (timeout);
1292 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1293 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1294 new_headers->len > 0) {
1298 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1300 /* Apply message count limit */
1301 /* If the number of messages exceeds the maximum, ask the
1302 * user to download them all,
1303 * as per the UI spec "Retrieval Limits" section in 4.4:
1305 if (new_headers->len > info->retrieve_limit) {
1306 /* TODO: Ask the user, instead of just
1308 * mail_nc_msg_count_limit_exceeded, with 'Get
1309 * all' and 'Newest only' buttons. */
1310 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1311 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1312 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1313 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1314 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1319 priv->total = MIN (new_headers->len, info->retrieve_limit);
1320 while (msg_num < priv->total) {
1322 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1323 TnyFolder *folder = tny_header_get_folder (header);
1324 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1325 ModestMailOperationState *state;
1329 /* We can not just use the mail operation because the
1330 values of done and total could change before the
1332 state = modest_mail_operation_clone_state (info->mail_op);
1333 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1334 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1335 pair, (GDestroyNotify) modest_pair_free);
1337 g_object_unref (msg);
1338 g_object_unref (folder);
1344 /* Get the number of new headers and free them */
1345 num_new_headers = new_headers->len;
1346 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1347 g_ptr_array_free (new_headers, FALSE);
1349 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1352 /* Perform send (if operation was not cancelled) */
1353 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1356 if (priv->account != NULL)
1357 g_object_unref (priv->account);
1358 priv->account = g_object_ref (info->transport_account);
1360 send_queue = modest_runtime_get_send_queue (info->transport_account);
1362 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1363 modest_tny_send_queue_try_to_send (send_queue);
1364 /* g_source_remove (timeout); */
1366 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1367 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1368 "cannot create a send queue for %s\n",
1369 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1370 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1373 /* Check if the operation was a success */
1375 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1377 /* Update the last updated key */
1378 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1379 set_last_updated_idle,
1380 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1381 (GDestroyNotify) g_free);
1386 if (info->callback) {
1387 UpdateAccountInfo *idle_info;
1389 /* This thread is not in the main lock */
1390 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1391 idle_info->mail_op = g_object_ref (info->mail_op);
1392 idle_info->new_headers = num_new_headers;
1393 idle_info->callback = info->callback;
1394 g_idle_add (idle_update_account_cb, idle_info);
1397 /* Notify about operation end. Note that the info could be
1398 freed before this idle happens, but the mail operation will
1400 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1403 g_object_unref (query);
1404 g_object_unref (all_folders);
1405 g_object_unref (info->account);
1406 g_object_unref (info->transport_account);
1407 g_free (info->retrieve_type);
1408 g_slice_free (UpdateAccountInfo, info);
1416 modest_mail_operation_update_account (ModestMailOperation *self,
1417 const gchar *account_name,
1418 UpdateAccountCallback callback,
1421 GThread *thread = NULL;
1422 UpdateAccountInfo *info = NULL;
1423 ModestMailOperationPrivate *priv = NULL;
1424 ModestAccountMgr *mgr = NULL;
1425 TnyStoreAccount *store_account = NULL;
1426 TnyTransportAccount *transport_account = NULL;
1428 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1429 g_return_val_if_fail (account_name, FALSE);
1431 /* Init mail operation. Set total and done to 0, and do not
1432 update them, this way the progress objects will know that
1433 we have no clue about the number of the objects */
1434 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1437 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1439 /* Get the Modest account */
1440 store_account = (TnyStoreAccount *)
1441 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1443 TNY_ACCOUNT_TYPE_STORE);
1445 /* Make sure that we have a connection, and request one
1447 * TODO: Is there some way to trigger this for every attempt to
1448 * use the network? */
1449 if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
1452 if (!store_account) {
1453 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1454 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1455 "cannot get tny store account for %s\n", account_name);
1460 /* Get the transport account, we can not do it in the thread
1461 due to some problems with dbus */
1462 transport_account = (TnyTransportAccount *)
1463 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1465 if (!transport_account) {
1466 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1467 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1468 "cannot get tny transport account for %s\n", account_name);
1472 /* Create the helper object */
1473 info = g_slice_new (UpdateAccountInfo);
1474 info->mail_op = self;
1475 info->account = store_account;
1476 info->transport_account = transport_account;
1477 info->callback = callback;
1478 info->user_data = user_data;
1480 /* Get the message size limit */
1481 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1482 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1483 if (info->max_size == 0)
1484 info->max_size = G_MAXINT;
1486 info->max_size = info->max_size * KB;
1488 /* Get per-account retrieval type */
1489 mgr = modest_runtime_get_account_mgr ();
1490 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1491 MODEST_ACCOUNT_RETRIEVE, FALSE);
1493 /* Get per-account message amount retrieval limit */
1494 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1495 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1496 if (info->retrieve_limit == 0)
1497 info->retrieve_limit = G_MAXINT;
1499 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1501 /* Set account busy */
1502 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1503 priv->account_name = g_strdup(account_name);
1505 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1510 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1512 callback (self, 0, user_data);
1513 modest_mail_operation_notify_end (self);
1517 /* ******************************************************************* */
1518 /* ************************** STORE ACTIONS ************************* */
1519 /* ******************************************************************* */
1523 modest_mail_operation_create_folder (ModestMailOperation *self,
1524 TnyFolderStore *parent,
1527 ModestMailOperationPrivate *priv;
1528 TnyFolder *new_folder = NULL;
1530 TnyList *list = tny_simple_list_new ();
1531 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1533 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1534 g_return_val_if_fail (name, NULL);
1536 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1538 /* Check for already existing folder */
1539 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1540 tny_folder_store_get_folders (parent, list, query, NULL);
1541 g_object_unref (G_OBJECT (query));
1543 if (tny_list_get_length (list) > 0) {
1544 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1545 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1546 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1547 _CS("ckdg_ib_folder_already_exists"));
1550 g_object_unref (G_OBJECT (list));
1553 if (TNY_IS_FOLDER (parent)) {
1554 /* Check folder rules */
1555 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1556 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1557 /* Set status failed and set an error */
1558 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1559 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1560 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1561 _("mail_in_ui_folder_create_error"));
1565 if (!strcmp (name, " ") || strchr (name, '/')) {
1566 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1567 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1568 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1569 _("mail_in_ui_folder_create_error"));
1573 /* Create the folder */
1574 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1575 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1577 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1580 /* Notify about operation end */
1581 modest_mail_operation_notify_end (self);
1587 modest_mail_operation_remove_folder (ModestMailOperation *self,
1589 gboolean remove_to_trash)
1591 TnyAccount *account;
1592 ModestMailOperationPrivate *priv;
1593 ModestTnyFolderRules rules;
1595 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1596 g_return_if_fail (TNY_IS_FOLDER (folder));
1598 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1600 /* Check folder rules */
1601 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1602 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1603 /* Set status failed and set an error */
1604 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1605 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1606 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1607 _("mail_in_ui_folder_delete_error"));
1611 /* Get the account */
1612 account = modest_tny_folder_get_account (folder);
1613 priv->account = g_object_ref(account);
1615 /* Delete folder or move to trash */
1616 if (remove_to_trash) {
1617 TnyFolder *trash_folder = NULL;
1618 trash_folder = modest_tny_account_get_special_folder (account,
1619 TNY_FOLDER_TYPE_TRASH);
1620 /* TODO: error_handling */
1622 modest_mail_operation_xfer_folder (self, folder,
1623 TNY_FOLDER_STORE (trash_folder),
1625 g_object_unref (trash_folder);
1628 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1630 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1631 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1634 g_object_unref (G_OBJECT (parent));
1636 g_object_unref (G_OBJECT (account));
1639 /* Notify about operation end */
1640 modest_mail_operation_notify_end (self);
1644 transfer_folder_status_cb (GObject *obj,
1648 ModestMailOperation *self;
1649 ModestMailOperationPrivate *priv;
1650 ModestMailOperationState *state;
1651 XFerMsgAsyncHelper *helper;
1653 g_return_if_fail (status != NULL);
1654 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1656 helper = (XFerMsgAsyncHelper *) user_data;
1657 g_return_if_fail (helper != NULL);
1659 self = helper->mail_op;
1660 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1662 priv->done = status->position;
1663 priv->total = status->of_total;
1665 state = modest_mail_operation_clone_state (self);
1666 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1667 gdk_threads_enter ();
1669 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1670 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1671 gdk_threads_leave ();
1673 g_slice_free (ModestMailOperationState, state);
1678 transfer_folder_cb (TnyFolder *folder,
1679 TnyFolderStore *into,
1681 TnyFolder *new_folder,
1685 XFerMsgAsyncHelper *helper;
1686 ModestMailOperation *self = NULL;
1687 ModestMailOperationPrivate *priv = NULL;
1689 helper = (XFerMsgAsyncHelper *) user_data;
1690 g_return_if_fail (helper != NULL);
1692 self = helper->mail_op;
1693 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1696 priv->error = g_error_copy (*err);
1698 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1699 } else if (cancelled) {
1700 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1701 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1702 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1703 _("Transference of %s was cancelled."),
1704 tny_folder_get_name (folder));
1707 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1710 /* Notify about operation end */
1711 modest_mail_operation_notify_end (self);
1713 /* If user defined callback function was defined, call it */
1714 if (helper->user_callback) {
1715 gdk_threads_enter ();
1716 helper->user_callback (priv->source, helper->user_data);
1717 gdk_threads_leave ();
1721 g_object_unref (helper->mail_op);
1722 g_slice_free (XFerMsgAsyncHelper, helper);
1727 * This function checks if the new name is a valid name for our local
1728 * folders account. The new name could not be the same than then name
1729 * of any of the mandatory local folders
1731 * We can not rely on tinymail because tinymail does not check the
1732 * name of the virtual folders that the account could have in the case
1733 * that we're doing a rename (because it directly calls Camel which
1734 * knows nothing about our virtual folders).
1736 * In the case of an actual copy/move (i.e. move/copy a folder between
1737 * accounts) tinymail uses the tny_folder_store_create_account which
1738 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1739 * checks the new name of the folder, so this call in that case
1740 * wouldn't be needed. *But* NOTE that if tinymail changes its
1741 * implementation (if folder transfers within the same account is no
1742 * longer implemented as a rename) this call will allow Modest to work
1745 * If the new name is not valid, this function will set the status to
1746 * failed and will set also an error in the mail operation
1749 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1750 TnyFolderStore *into,
1751 const gchar *new_name)
1753 if (TNY_IS_ACCOUNT (into) &&
1754 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1755 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1757 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1758 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1759 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1760 _("FIXME: folder name already in use"));
1767 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1769 TnyFolderStore *parent,
1770 gboolean delete_original,
1771 XferMsgsAsynUserCallback user_callback,
1774 ModestMailOperationPrivate *priv = NULL;
1775 ModestTnyFolderRules parent_rules = 0, rules;
1776 XFerMsgAsyncHelper *helper = NULL;
1778 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1779 g_return_if_fail (TNY_IS_FOLDER (folder));
1781 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1783 /* Get account and set it into mail_operation */
1784 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1785 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1787 /* Get folder rules */
1788 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1789 if (TNY_IS_FOLDER (parent))
1790 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1792 /* The moveable restriction is applied also to copy operation */
1793 if ((gpointer) parent == (gpointer) folder ||
1794 (!TNY_IS_FOLDER_STORE (parent)) ||
1795 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1796 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1797 /* Set status failed and set an error */
1798 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1799 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1800 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1801 _("mail_in_ui_folder_move_target_error"));
1803 /* Notify the queue */
1804 modest_mail_operation_notify_end (self);
1805 } else if (TNY_IS_FOLDER (parent) &&
1806 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1807 /* Set status failed and set an error */
1808 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1809 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1810 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1811 _("FIXME: parent folder does not accept new folders"));
1813 /* Notify the queue */
1814 modest_mail_operation_notify_end (self);
1818 /* Check that the new folder name is not used by any
1819 special local folder */
1820 if (new_name_valid_if_local_account (priv, parent,
1821 tny_folder_get_name (folder))) {
1822 /* Create the helper */
1823 helper = g_slice_new0 (XFerMsgAsyncHelper);
1824 helper->mail_op = g_object_ref(self);
1825 helper->dest_folder = NULL;
1826 helper->headers = NULL;
1827 helper->user_callback = user_callback;
1828 helper->user_data = user_data;
1830 /* Move/Copy folder */
1831 tny_folder_copy_async (folder,
1833 tny_folder_get_name (folder),
1836 transfer_folder_status_cb,
1839 modest_mail_operation_notify_end (self);
1845 modest_mail_operation_rename_folder (ModestMailOperation *self,
1849 ModestMailOperationPrivate *priv;
1850 ModestTnyFolderRules rules;
1851 XFerMsgAsyncHelper *helper;
1853 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1854 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1855 g_return_if_fail (name);
1857 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1859 /* Get account and set it into mail_operation */
1860 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1862 /* Check folder rules */
1863 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1864 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1865 /* Set status failed and set an error */
1866 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1867 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1868 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1869 _("FIXME: unable to rename"));
1871 /* Notify about operation end */
1872 modest_mail_operation_notify_end (self);
1873 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1874 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1875 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1876 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1877 _("FIXME: unable to rename"));
1878 /* Notify about operation end */
1879 modest_mail_operation_notify_end (self);
1881 TnyFolderStore *into;
1883 into = tny_folder_get_folder_store (folder);
1885 /* Check that the new folder name is not used by any
1886 special local folder */
1887 if (new_name_valid_if_local_account (priv, into, name)) {
1888 /* Create the helper */
1889 helper = g_slice_new0 (XFerMsgAsyncHelper);
1890 helper->mail_op = g_object_ref(self);
1891 helper->dest_folder = NULL;
1892 helper->headers = NULL;
1893 helper->user_callback = NULL;
1894 helper->user_data = NULL;
1896 /* Rename. Camel handles folder subscription/unsubscription */
1897 tny_folder_copy_async (folder, into, name, TRUE,
1899 transfer_folder_status_cb,
1902 modest_mail_operation_notify_end (self);
1904 g_object_unref (into);
1908 /* ******************************************************************* */
1909 /* ************************** MSG ACTIONS ************************* */
1910 /* ******************************************************************* */
1912 void modest_mail_operation_get_msg (ModestMailOperation *self,
1914 GetMsgAsyncUserCallback user_callback,
1917 GetMsgAsyncHelper *helper = NULL;
1919 ModestMailOperationPrivate *priv;
1921 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1922 g_return_if_fail (TNY_IS_HEADER (header));
1924 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1925 folder = tny_header_get_folder (header);
1927 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1929 /* Get message from folder */
1931 /* Get account and set it into mail_operation */
1932 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1934 helper = g_slice_new0 (GetMsgAsyncHelper);
1935 helper->mail_op = self;
1936 helper->user_callback = user_callback;
1937 helper->user_data = user_data;
1938 helper->header = g_object_ref (header);
1940 // The callback's reference so that the mail op is not
1941 // finalized until the async operation is completed even if
1942 // the user canceled the request meanwhile.
1943 g_object_ref (G_OBJECT (helper->mail_op));
1945 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1947 g_object_unref (G_OBJECT (folder));
1949 /* Set status failed and set an error */
1950 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1951 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1952 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1953 _("Error trying to get a message. No folder found for header"));
1955 /* Notify the queue */
1956 modest_mail_operation_notify_end (self);
1961 get_msg_cb (TnyFolder *folder,
1967 GetMsgAsyncHelper *helper = NULL;
1968 ModestMailOperation *self = NULL;
1969 ModestMailOperationPrivate *priv = NULL;
1971 helper = (GetMsgAsyncHelper *) user_data;
1972 g_return_if_fail (helper != NULL);
1973 self = helper->mail_op;
1974 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1975 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1977 /* Check errors and cancel */
1979 priv->error = g_error_copy (*error);
1980 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1981 } else if (cancelled) {
1982 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1983 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1984 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1985 _("Error trying to refresh the contents of %s"),
1986 tny_folder_get_name (folder));
1988 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1991 /* If user defined callback function was defined, call it even
1992 if the operation failed*/
1993 if (helper->user_callback) {
1994 /* This callback is called into an iddle by tinymail,
1995 and idles are not in the main lock */
1996 gdk_threads_enter ();
1997 helper->user_callback (self, helper->header, msg, helper->user_data);
1998 gdk_threads_leave ();
2001 /* Notify about operation end */
2002 modest_mail_operation_notify_end (self);
2004 g_object_unref (helper->mail_op);
2005 g_object_unref (helper->header);
2006 g_slice_free (GetMsgAsyncHelper, helper);
2011 get_msg_status_cb (GObject *obj,
2015 GetMsgAsyncHelper *helper = NULL;
2016 ModestMailOperation *self;
2017 ModestMailOperationPrivate *priv;
2018 ModestMailOperationState *state;
2020 g_return_if_fail (status != NULL);
2021 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2023 helper = (GetMsgAsyncHelper *) user_data;
2024 g_return_if_fail (helper != NULL);
2026 self = helper->mail_op;
2027 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2032 state = modest_mail_operation_clone_state (self);
2033 state->bytes_done = status->position;
2034 state->bytes_total = status->of_total;
2035 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2036 gdk_threads_enter ();
2038 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2039 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2040 gdk_threads_leave ();
2042 g_slice_free (ModestMailOperationState, state);
2045 /****************************************************/
2047 ModestMailOperation *mail_op;
2049 GetMsgAsyncUserCallback user_callback;
2051 GDestroyNotify notify;
2055 GetMsgAsyncUserCallback user_callback;
2059 ModestMailOperation *mail_op;
2060 } NotifyGetMsgsInfo;
2064 * Used by get_msgs_full_thread to call the user_callback for each
2065 * message that has been read
2068 notify_get_msgs_full (gpointer data)
2070 NotifyGetMsgsInfo *info;
2072 info = (NotifyGetMsgsInfo *) data;
2074 /* Call the user callback. Idles are not in the main lock, so
2076 gdk_threads_enter ();
2077 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2078 gdk_threads_leave ();
2080 g_slice_free (NotifyGetMsgsInfo, info);
2086 * Used by get_msgs_full_thread to free al the thread resources and to
2087 * call the destroy function for the passed user_data
2090 get_msgs_full_destroyer (gpointer data)
2092 GetFullMsgsInfo *info;
2094 info = (GetFullMsgsInfo *) data;
2097 gdk_threads_enter ();
2098 info->notify (info->user_data);
2099 gdk_threads_leave ();
2103 g_object_unref (info->headers);
2104 g_slice_free (GetFullMsgsInfo, info);
2110 get_msgs_full_thread (gpointer thr_user_data)
2112 GetFullMsgsInfo *info;
2113 ModestMailOperationPrivate *priv = NULL;
2114 TnyIterator *iter = NULL;
2116 info = (GetFullMsgsInfo *) thr_user_data;
2117 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2119 iter = tny_list_create_iterator (info->headers);
2120 while (!tny_iterator_is_done (iter)) {
2124 header = TNY_HEADER (tny_iterator_get_current (iter));
2125 folder = tny_header_get_folder (header);
2127 /* Get message from folder */
2130 /* The callback will call it per each header */
2131 msg = tny_folder_get_msg (folder, header, &(priv->error));
2134 ModestMailOperationState *state;
2139 /* notify progress */
2140 state = modest_mail_operation_clone_state (info->mail_op);
2141 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2142 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2143 pair, (GDestroyNotify) modest_pair_free);
2145 /* The callback is the responsible for
2146 freeing the message */
2147 if (info->user_callback) {
2148 NotifyGetMsgsInfo *info_notify;
2149 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2150 info_notify->user_callback = info->user_callback;
2151 info_notify->mail_op = info->mail_op;
2152 info_notify->header = g_object_ref (header);
2153 info_notify->msg = g_object_ref (msg);
2154 info_notify->user_data = info->user_data;
2155 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2156 notify_get_msgs_full,
2159 g_object_unref (msg);
2162 /* Set status failed and set an error */
2163 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2164 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2165 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2166 "Error trying to get a message. No folder found for header");
2170 g_object_unref (header);
2172 tny_iterator_next (iter);
2175 /* Set operation status */
2176 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2177 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2179 /* Notify about operation end */
2180 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2182 /* Free thread resources. Will be called after all previous idles */
2183 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2189 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2190 TnyList *header_list,
2191 GetMsgAsyncUserCallback user_callback,
2193 GDestroyNotify notify)
2195 TnyHeader *header = NULL;
2196 TnyFolder *folder = NULL;
2198 ModestMailOperationPrivate *priv = NULL;
2199 GetFullMsgsInfo *info = NULL;
2200 gboolean size_ok = TRUE;
2202 TnyIterator *iter = NULL;
2204 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2206 /* Init mail operation */
2207 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2208 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2210 priv->total = tny_list_get_length(header_list);
2212 /* Get account and set it into mail_operation */
2213 if (tny_list_get_length (header_list) >= 1) {
2214 iter = tny_list_create_iterator (header_list);
2215 header = TNY_HEADER (tny_iterator_get_current (iter));
2217 folder = tny_header_get_folder (header);
2219 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2221 g_object_unref (folder);
2224 g_object_unref (header);
2227 if (tny_list_get_length (header_list) == 1) {
2228 g_object_unref (iter);
2233 /* Get msg size limit */
2234 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2235 MODEST_CONF_MSG_SIZE_LIMIT,
2238 g_clear_error (&(priv->error));
2239 max_size = G_MAXINT;
2241 max_size = max_size * KB;
2244 /* Check message size limits. If there is only one message
2245 always retrieve it */
2247 while (!tny_iterator_is_done (iter) && size_ok) {
2248 header = TNY_HEADER (tny_iterator_get_current (iter));
2250 if (tny_header_get_message_size (header) >= max_size)
2252 g_object_unref (header);
2255 tny_iterator_next (iter);
2257 g_object_unref (iter);
2261 /* Create the info */
2262 info = g_slice_new0 (GetFullMsgsInfo);
2263 info->mail_op = self;
2264 info->user_callback = user_callback;
2265 info->user_data = user_data;
2266 info->headers = g_object_ref (header_list);
2267 info->notify = notify;
2269 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2271 /* Set status failed and set an error */
2272 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2273 /* FIXME: the error msg is different for pop */
2274 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2275 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2276 _("emev_ni_ui_imap_msg_size_exceed_error"));
2277 /* Remove from queue and free resources */
2278 modest_mail_operation_notify_end (self);
2286 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2287 gboolean remove_to_trash /*ignored*/)
2290 ModestMailOperationPrivate *priv;
2292 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2293 g_return_if_fail (TNY_IS_HEADER (header));
2295 if (remove_to_trash)
2296 g_warning ("remove to trash is not implemented");
2298 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2299 folder = tny_header_get_folder (header);
2301 /* Get account and set it into mail_operation */
2302 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2304 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2306 /* remove message from folder */
2307 tny_folder_remove_msg (folder, header, &(priv->error));
2308 /* if (!priv->error) { */
2309 /* tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED); */
2310 /* tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN); */
2312 /* if (TNY_IS_CAMEL_IMAP_FOLDER (folder)) */
2313 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* FALSE --> don't expunge *\/ */
2314 /* /\* tny_folder_sync (folder, FALSE, &(priv->error)); /\\* FALSE --> don't expunge *\\/ *\/ */
2315 /* else if (TNY_IS_CAMEL_POP_FOLDER (folder)) */
2316 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* TRUE --> dont expunge *\/ */
2317 /* /\* tny_folder_sync (folder, TRUE, &(priv->error)); /\\* TRUE --> expunge *\\/ *\/ */
2319 /* /\* local folders *\/ */
2320 /* tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /\* TRUE --> expunge *\/ */
2321 /* /\* tny_folder_sync (folder, TRUE, &(priv->error)); /\\* TRUE --> expunge *\\/ *\/ */
2327 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2329 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2332 g_object_unref (G_OBJECT (folder));
2334 /* Notify about operation end */
2335 modest_mail_operation_notify_end (self);
2339 transfer_msgs_status_cb (GObject *obj,
2343 XFerMsgAsyncHelper *helper = NULL;
2344 ModestMailOperation *self;
2345 ModestMailOperationPrivate *priv;
2346 ModestMailOperationState *state;
2349 g_return_if_fail (status != NULL);
2350 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2352 helper = (XFerMsgAsyncHelper *) user_data;
2353 g_return_if_fail (helper != NULL);
2355 self = helper->mail_op;
2356 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2358 priv->done = status->position;
2359 priv->total = status->of_total;
2361 state = modest_mail_operation_clone_state (self);
2362 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2363 gdk_threads_enter ();
2365 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2366 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2367 gdk_threads_leave ();
2369 g_slice_free (ModestMailOperationState, state);
2374 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2376 XFerMsgAsyncHelper *helper;
2377 ModestMailOperation *self;
2378 ModestMailOperationPrivate *priv;
2379 TnyIterator *iter = NULL;
2380 TnyHeader *header = NULL;
2382 helper = (XFerMsgAsyncHelper *) user_data;
2383 self = helper->mail_op;
2385 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2388 priv->error = g_error_copy (*err);
2390 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2391 } else if (cancelled) {
2392 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2393 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2394 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2395 _("Error trying to refresh the contents of %s"),
2396 tny_folder_get_name (folder));
2399 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2403 /* Mark headers as deleted and seen */
2404 if ((helper->delete) &&
2405 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2406 iter = tny_list_create_iterator (helper->headers);
2407 while (!tny_iterator_is_done (iter)) {
2408 header = TNY_HEADER (tny_iterator_get_current (iter));
2409 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2410 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2411 g_object_unref (header);
2413 tny_iterator_next (iter);
2419 /* Notify about operation end */
2420 modest_mail_operation_notify_end (self);
2422 /* If user defined callback function was defined, call it */
2423 if (helper->user_callback) {
2424 gdk_threads_enter ();
2425 helper->user_callback (priv->source, helper->user_data);
2426 gdk_threads_leave ();
2430 if (helper->headers)
2431 g_object_unref (helper->headers);
2432 if (helper->dest_folder)
2433 g_object_unref (helper->dest_folder);
2434 if (helper->mail_op)
2435 g_object_unref (helper->mail_op);
2437 g_object_unref (folder);
2439 g_object_unref (iter);
2440 g_slice_free (XFerMsgAsyncHelper, helper);
2445 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2448 gboolean delete_original,
2449 XferMsgsAsynUserCallback user_callback,
2452 ModestMailOperationPrivate *priv = NULL;
2453 TnyIterator *iter = NULL;
2454 TnyFolder *src_folder = NULL;
2455 XFerMsgAsyncHelper *helper = NULL;
2456 TnyHeader *header = NULL;
2457 ModestTnyFolderRules rules = 0;
2458 const gchar *id1 = NULL;
2459 const gchar *id2 = NULL;
2460 gboolean same_folder = FALSE;
2462 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2463 g_return_if_fail (TNY_IS_LIST (headers));
2464 g_return_if_fail (TNY_IS_FOLDER (folder));
2466 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2469 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2471 /* Apply folder rules */
2472 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2473 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2474 /* Set status failed and set an error */
2475 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2476 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2477 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2478 _CS("ckct_ib_unable_to_paste_here"));
2479 /* Notify the queue */
2480 modest_mail_operation_notify_end (self);
2484 /* Get source folder */
2485 iter = tny_list_create_iterator (headers);
2486 header = TNY_HEADER (tny_iterator_get_current (iter));
2488 src_folder = tny_header_get_folder (header);
2489 g_object_unref (header);
2492 g_object_unref (iter);
2494 /* Check folder source and destination */
2495 id1 = tny_folder_get_id (src_folder);
2496 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2497 same_folder = !g_ascii_strcasecmp (id1, id2);
2499 /* Set status failed and set an error */
2500 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2501 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2502 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2503 _("mcen_ib_unable_to_copy_samefolder"));
2505 /* Notify the queue */
2506 modest_mail_operation_notify_end (self);
2509 g_object_unref (src_folder);
2513 /* Create the helper */
2514 helper = g_slice_new0 (XFerMsgAsyncHelper);
2515 helper->mail_op = g_object_ref(self);
2516 helper->dest_folder = g_object_ref(folder);
2517 helper->headers = g_object_ref(headers);
2518 helper->user_callback = user_callback;
2519 helper->user_data = user_data;
2520 helper->delete = delete_original;
2522 /* Get account and set it into mail_operation */
2523 priv->account = modest_tny_folder_get_account (src_folder);
2525 /* Transfer messages */
2526 tny_folder_transfer_msgs_async (src_folder,
2531 transfer_msgs_status_cb,
2537 on_refresh_folder (TnyFolder *folder,
2542 RefreshAsyncHelper *helper = NULL;
2543 ModestMailOperation *self = NULL;
2544 ModestMailOperationPrivate *priv = NULL;
2546 helper = (RefreshAsyncHelper *) user_data;
2547 self = helper->mail_op;
2548 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2550 g_return_if_fail(priv!=NULL);
2553 priv->error = g_error_copy (*error);
2554 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2559 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2560 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2561 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2562 _("Error trying to refresh the contents of %s"),
2563 tny_folder_get_name (folder));
2567 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2569 /* Call user defined callback, if it exists */
2570 if (helper->user_callback) {
2571 gdk_threads_enter ();
2572 helper->user_callback (self, folder, helper->user_data);
2573 gdk_threads_leave ();
2577 g_slice_free (RefreshAsyncHelper, helper);
2579 /* Notify about operation end */
2580 modest_mail_operation_notify_end (self);
2581 g_object_unref(self);
2585 on_refresh_folder_status_update (GObject *obj,
2589 RefreshAsyncHelper *helper = NULL;
2590 ModestMailOperation *self = NULL;
2591 ModestMailOperationPrivate *priv = NULL;
2592 ModestMailOperationState *state;
2594 g_return_if_fail (user_data != NULL);
2595 g_return_if_fail (status != NULL);
2596 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2598 helper = (RefreshAsyncHelper *) user_data;
2599 self = helper->mail_op;
2600 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2602 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2604 priv->done = status->position;
2605 priv->total = status->of_total;
2607 state = modest_mail_operation_clone_state (self);
2608 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2609 gdk_threads_enter ();
2611 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2612 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2613 gdk_threads_leave ();
2615 g_slice_free (ModestMailOperationState, state);
2619 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2621 RefreshAsyncUserCallback user_callback,
2624 ModestMailOperationPrivate *priv = NULL;
2625 RefreshAsyncHelper *helper = NULL;
2627 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2629 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2631 /* Get account and set it into mail_operation */
2632 priv->account = modest_tny_folder_get_account (folder);
2634 /* Create the helper */
2635 helper = g_slice_new0 (RefreshAsyncHelper);
2636 helper->mail_op = g_object_ref(self);
2637 helper->user_callback = user_callback;
2638 helper->user_data = user_data;
2640 /* Refresh the folder. TODO: tinymail could issue a status
2641 updates before the callback call then this could happen. We
2642 must review the design */
2643 tny_folder_refresh_async (folder,
2645 on_refresh_folder_status_update,
2651 * It's used by the mail operation queue to notify the observers
2652 * attached to that signal that the operation finished. We need to use
2653 * that because tinymail does not give us the progress of a given
2654 * operation when it finishes (it directly calls the operation
2658 modest_mail_operation_notify_end (ModestMailOperation *self)
2660 ModestMailOperationState *state;
2661 ModestMailOperationPrivate *priv = NULL;
2663 g_return_if_fail (self);
2665 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2667 /* Set the account back to not busy */
2668 if (priv->account_name) {
2669 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2670 priv->account_name, FALSE);
2671 g_free(priv->account_name);
2672 priv->account_name = NULL;
2675 /* Notify the observers about the mail operation end */
2676 /* We do not wrapp this emission because we assume that this
2677 function is always called from within the main lock */
2678 state = modest_mail_operation_clone_state (self);
2679 g_warning ("EXAMINE SITUATION: "
2680 "self might be NULL after this function (%s) returns",
2682 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2683 g_slice_free (ModestMailOperationState, state);