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"
61 #define GET_SIZE_BUFFER_SIZE 128
64 * Remove all these #ifdef stuff when the tinymail's idle calls become
67 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
69 /* 'private'/'protected' functions */
70 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
71 static void modest_mail_operation_init (ModestMailOperation *obj);
72 static void modest_mail_operation_finalize (GObject *obj);
74 static void get_msg_cb (TnyFolder *folder,
80 static void get_msg_status_cb (GObject *obj,
84 static void modest_mail_operation_notify_end (ModestMailOperation *self);
86 enum _ModestMailOperationSignals
88 PROGRESS_CHANGED_SIGNAL,
93 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
94 struct _ModestMailOperationPrivate {
101 ErrorCheckingUserCallback error_checking;
102 gpointer error_checking_user_data;
103 ModestMailOperationStatus status;
104 ModestMailOperationTypeOperation op_type;
107 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
108 MODEST_TYPE_MAIL_OPERATION, \
109 ModestMailOperationPrivate))
111 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
112 priv->status = new_status;\
115 typedef struct _GetMsgAsyncHelper {
116 ModestMailOperation *mail_op;
118 GetMsgAsyncUserCallback user_callback;
122 typedef struct _RefreshAsyncHelper {
123 ModestMailOperation *mail_op;
124 RefreshAsyncUserCallback user_callback;
126 } RefreshAsyncHelper;
128 typedef struct _XFerMsgAsyncHelper
130 ModestMailOperation *mail_op;
132 TnyFolder *dest_folder;
133 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
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;
708 /* Call mail operation */
709 modest_mail_operation_send_mail (self, info->transport_account, msg);
711 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
713 if (info->draft_msg != NULL) {
714 header = tny_msg_get_header (info->draft_msg);
715 /* Note: This can fail (with a warning) if the message is not really already in a folder,
716 * because this function requires it to have a UID. */
717 tny_folder_remove_msg (folder, header, NULL);
718 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
719 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
720 g_object_unref (header);
721 g_object_unref (folder);
727 g_object_unref (info->draft_msg);
728 if (info->transport_account)
729 g_object_unref (info->transport_account);
730 g_slice_free (SendNewMailInfo, info);
731 modest_mail_operation_notify_end (self);
735 modest_mail_operation_send_new_mail (ModestMailOperation *self,
736 TnyTransportAccount *transport_account,
738 const gchar *from, const gchar *to,
739 const gchar *cc, const gchar *bcc,
740 const gchar *subject, const gchar *plain_body,
741 const gchar *html_body,
742 const GList *attachments_list,
743 TnyHeaderFlags priority_flags)
745 ModestMailOperationPrivate *priv = NULL;
746 SendNewMailInfo *info;
748 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
749 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
751 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
753 /* Check parametters */
755 /* Set status failed and set an error */
756 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
757 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
758 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
759 _("Error trying to send a mail. You need to set at least one recipient"));
762 info = g_slice_new0 (SendNewMailInfo);
763 info->transport_account = transport_account;
764 if (transport_account)
765 g_object_ref (transport_account);
766 info->draft_msg = draft_msg;
768 g_object_ref (draft_msg);
769 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
770 attachments_list, priority_flags,
771 modest_mail_operation_send_new_mail_cb, info);
777 TnyTransportAccount *transport_account;
779 ModestMsgEditWindow *edit_window;
783 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
787 TnyFolder *folder = NULL;
788 TnyHeader *header = NULL;
789 ModestMailOperationPrivate *priv = NULL;
790 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
792 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
794 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
795 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
796 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
797 "modest: failed to create a new msg\n");
801 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
803 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
804 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
805 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
806 "modest: failed to create a new msg\n");
810 if (info->draft_msg != NULL) {
811 header = tny_msg_get_header (info->draft_msg);
812 /* Remove the old draft expunging it */
813 tny_folder_remove_msg (folder, header, NULL);
814 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
815 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
816 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
817 g_object_unref (header);
821 tny_folder_add_msg (folder, msg, &(priv->error));
824 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
826 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
828 if (info->edit_window)
829 modest_msg_edit_window_set_draft (info->edit_window, msg);
834 g_object_unref (G_OBJECT(folder));
835 if (info->edit_window)
836 g_object_unref (G_OBJECT(info->edit_window));
838 g_object_unref (G_OBJECT (info->draft_msg));
839 if (info->transport_account)
840 g_object_unref (G_OBJECT(info->transport_account));
841 g_slice_free (SaveToDraftsInfo, info);
843 modest_mail_operation_notify_end (self);
847 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
848 TnyTransportAccount *transport_account,
850 ModestMsgEditWindow *edit_window,
851 const gchar *from, const gchar *to,
852 const gchar *cc, const gchar *bcc,
853 const gchar *subject, const gchar *plain_body,
854 const gchar *html_body,
855 const GList *attachments_list,
856 TnyHeaderFlags priority_flags)
858 ModestMailOperationPrivate *priv = NULL;
859 SaveToDraftsInfo *info = NULL;
861 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
862 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
864 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
866 /* Get account and set it into mail_operation */
867 priv->account = g_object_ref (transport_account);
869 info = g_slice_new0 (SaveToDraftsInfo);
870 info->transport_account = g_object_ref (transport_account);
871 info->draft_msg = draft_msg;
873 g_object_ref (draft_msg);
874 info->edit_window = edit_window;
876 g_object_ref (edit_window);
878 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
879 attachments_list, priority_flags,
880 modest_mail_operation_save_to_drafts_cb, info);
886 ModestMailOperation *mail_op;
887 TnyStoreAccount *account;
888 TnyTransportAccount *transport_account;
891 gchar *retrieve_type;
893 UpdateAccountCallback callback;
900 ModestMailOperation *mail_op;
901 TnyMimePart *mime_part;
903 GetMimePartSizeCallback callback;
905 } GetMimePartSizeInfo;
907 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
908 /* We use this folder observer to track the headers that have been
909 * added to a folder */
912 TnyList *new_headers;
913 } InternalFolderObserver;
917 } InternalFolderObserverClass;
919 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
921 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
922 internal_folder_observer,
924 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
928 foreach_add_item (gpointer header, gpointer user_data)
930 tny_list_prepend (TNY_LIST (user_data),
931 g_object_ref (G_OBJECT (header)));
934 /* This is the method that looks for new messages in a folder */
936 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
938 InternalFolderObserver *derived = (InternalFolderObserver *)self;
940 TnyFolderChangeChanged changed;
942 changed = tny_folder_change_get_changed (change);
944 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
947 /* Get added headers */
948 list = tny_simple_list_new ();
949 tny_folder_change_get_added_headers (change, list);
951 /* Add them to the folder observer */
952 tny_list_foreach (list, foreach_add_item,
953 derived->new_headers);
955 g_object_unref (G_OBJECT (list));
960 internal_folder_observer_init (InternalFolderObserver *self)
962 self->new_headers = tny_simple_list_new ();
965 internal_folder_observer_finalize (GObject *object)
967 InternalFolderObserver *self;
969 self = (InternalFolderObserver *) object;
970 g_object_unref (self->new_headers);
972 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
975 tny_folder_observer_init (TnyFolderObserverIface *iface)
977 iface->update_func = internal_folder_observer_update;
980 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
982 GObjectClass *object_class;
984 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
985 object_class = (GObjectClass*) klass;
986 object_class->finalize = internal_folder_observer_finalize;
992 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
995 TnyList *folders = tny_simple_list_new ();
997 tny_folder_store_get_folders (store, folders, query, NULL);
998 iter = tny_list_create_iterator (folders);
1000 while (!tny_iterator_is_done (iter)) {
1002 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1004 tny_list_prepend (all_folders, G_OBJECT (folder));
1005 recurse_folders (folder, query, all_folders);
1006 g_object_unref (G_OBJECT (folder));
1009 tny_iterator_next (iter);
1011 g_object_unref (G_OBJECT (iter));
1012 g_object_unref (G_OBJECT (folders));
1016 * Issues the "progress-changed" signal. The timer won't be removed,
1017 * so you must call g_source_remove to stop the signal emission
1020 idle_notify_progress (gpointer data)
1022 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1023 ModestMailOperationState *state;
1025 state = modest_mail_operation_clone_state (mail_op);
1026 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1027 gdk_threads_enter ();
1029 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1030 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1031 gdk_threads_leave ();
1033 g_slice_free (ModestMailOperationState, state);
1039 * Issues the "progress-changed" signal and removes the timer. It uses
1040 * a lock to ensure that the progress information of the mail
1041 * operation is not modified while there are notifications pending
1044 idle_notify_progress_once (gpointer data)
1048 pair = (ModestPair *) data;
1050 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1051 gdk_threads_enter ();
1053 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1054 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1055 gdk_threads_leave ();
1058 /* Free the state and the reference to the mail operation */
1059 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1060 g_object_unref (pair->first);
1066 * Used to notify the queue from the main
1067 * loop. We call it inside an idle call to achieve that
1070 idle_notify_queue (gpointer data)
1072 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1074 /* Do not need to block, the notify end will do it for us */
1075 modest_mail_operation_notify_end (mail_op);
1076 g_object_unref (mail_op);
1082 compare_headers_by_date (gconstpointer a,
1085 TnyHeader **header1, **header2;
1086 time_t sent1, sent2;
1088 header1 = (TnyHeader **) a;
1089 header2 = (TnyHeader **) b;
1091 sent1 = tny_header_get_date_sent (*header1);
1092 sent2 = tny_header_get_date_sent (*header2);
1094 /* We want the most recent ones (greater time_t) at the
1103 set_last_updated_idle (gpointer data)
1105 gdk_threads_enter ();
1107 /* It does not matter if the time is not exactly the same than
1108 the time when this idle was called, it's just an
1109 approximation and it won't be very different */
1110 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1112 MODEST_ACCOUNT_LAST_UPDATED,
1116 gdk_threads_leave ();
1122 idle_update_account_cb (gpointer data)
1124 UpdateAccountInfo *idle_info;
1126 idle_info = (UpdateAccountInfo *) data;
1128 gdk_threads_enter ();
1129 idle_info->callback (idle_info->mail_op,
1130 idle_info->new_headers,
1131 idle_info->user_data);
1132 gdk_threads_leave ();
1135 g_object_unref (idle_info->mail_op);
1143 update_account_thread (gpointer thr_user_data)
1145 static gboolean first_time = TRUE;
1146 UpdateAccountInfo *info = NULL;
1147 TnyList *all_folders = NULL;
1148 GPtrArray *new_headers = NULL;
1149 TnyIterator *iter = NULL;
1150 TnyFolderStoreQuery *query = NULL;
1151 ModestMailOperationPrivate *priv = NULL;
1152 ModestTnySendQueue *send_queue = NULL;
1153 gint num_new_headers = 0;
1155 info = (UpdateAccountInfo *) thr_user_data;
1156 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1158 /* Get account and set it into mail_operation */
1159 priv->account = g_object_ref (info->account);
1162 * Previousl, we did this for POP3, to do a logout-login upon send/receive,
1163 * because many POP-servers (like Gmail) do not
1164 * show any updates unless we do that.
1165 * But that didn't work with gmail anyway,
1166 * and tinymail now takes care of this itself by disconnecting
1167 * automatically after using the connection.
1170 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT (priv->account))
1171 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1174 /* Get all the folders. We can do it synchronously because
1175 we're already running in a different thread than the UI */
1176 all_folders = tny_simple_list_new ();
1177 query = tny_folder_store_query_new ();
1178 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1179 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1184 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1188 iter = tny_list_create_iterator (all_folders);
1189 while (!tny_iterator_is_done (iter)) {
1190 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1192 recurse_folders (folder, query, all_folders);
1193 g_object_unref (folder);
1195 tny_iterator_next (iter);
1197 g_object_unref (G_OBJECT (iter));
1199 /* Update status and notify. We need to call the notification
1200 with a source function in order to call it from the main
1201 loop. We need that in order not to get into trouble with
1202 Gtk+. We use a timeout in order to provide more status
1203 information, because the sync tinymail call does not
1204 provide it for the moment */
1205 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1207 /* Refresh folders */
1208 num_new_headers = 0;
1209 new_headers = g_ptr_array_new ();
1210 iter = tny_list_create_iterator (all_folders);
1212 while (!tny_iterator_is_done (iter) && !priv->error &&
1213 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1215 InternalFolderObserver *observer;
1216 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1218 /* Refresh the folder */
1219 /* Our observer receives notification of new emails during folder refreshes,
1220 * so we can use observer->new_headers.
1222 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1223 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1225 /* This gets the status information (headers) from the server.
1226 * We use the blocking version, because we are already in a separate
1230 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1231 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1234 /* If the retrieve type is full messages, refresh and get the messages */
1235 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1237 iter = tny_list_create_iterator (observer->new_headers);
1238 while (!tny_iterator_is_done (iter)) {
1239 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1241 /* Apply per-message size limits */
1242 if (tny_header_get_message_size (header) < info->max_size)
1243 g_ptr_array_add (new_headers, g_object_ref (header));
1245 g_object_unref (header);
1246 tny_iterator_next (iter);
1248 g_object_unref (iter);
1250 /* We do not need to do it the first time
1251 because it's automatically done by the tree
1253 if (G_UNLIKELY (!first_time))
1254 tny_folder_poke_status (TNY_FOLDER (folder));
1256 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1257 g_object_unref (observer);
1261 g_object_unref (G_OBJECT (folder));
1264 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1266 tny_iterator_next (iter);
1269 g_object_unref (G_OBJECT (iter));
1270 g_source_remove (timeout);
1272 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1273 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1274 new_headers->len > 0) {
1278 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1280 /* Apply message count limit */
1281 /* If the number of messages exceeds the maximum, ask the
1282 * user to download them all,
1283 * as per the UI spec "Retrieval Limits" section in 4.4:
1285 if (new_headers->len > info->retrieve_limit) {
1286 /* TODO: Ask the user, instead of just
1288 * mail_nc_msg_count_limit_exceeded, with 'Get
1289 * all' and 'Newest only' buttons. */
1290 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1291 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1292 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1293 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1294 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1299 priv->total = MIN (new_headers->len, info->retrieve_limit);
1300 while (msg_num < priv->total) {
1302 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1303 TnyFolder *folder = tny_header_get_folder (header);
1304 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1305 ModestMailOperationState *state;
1309 /* We can not just use the mail operation because the
1310 values of done and total could change before the
1312 state = modest_mail_operation_clone_state (info->mail_op);
1313 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1314 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1315 pair, (GDestroyNotify) modest_pair_free);
1317 g_object_unref (msg);
1318 g_object_unref (folder);
1324 /* Get the number of new headers and free them */
1325 num_new_headers = new_headers->len;
1326 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1327 g_ptr_array_free (new_headers, FALSE);
1329 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1332 /* Perform send (if operation was not cancelled) */
1333 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1336 if (priv->account != NULL)
1337 g_object_unref (priv->account);
1338 priv->account = g_object_ref (info->transport_account);
1340 send_queue = modest_runtime_get_send_queue (info->transport_account);
1342 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1343 modest_tny_send_queue_try_to_send (send_queue);
1344 /* g_source_remove (timeout); */
1346 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1347 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1348 "cannot create a send queue for %s\n",
1349 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1350 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1353 /* Check if the operation was a success */
1355 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1357 /* Update the last updated key */
1358 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1359 set_last_updated_idle,
1360 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1361 (GDestroyNotify) g_free);
1366 if (info->callback) {
1367 UpdateAccountInfo *idle_info;
1369 /* This thread is not in the main lock */
1370 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1371 idle_info->mail_op = g_object_ref (info->mail_op);
1372 idle_info->new_headers = num_new_headers;
1373 idle_info->callback = info->callback;
1374 g_idle_add (idle_update_account_cb, idle_info);
1377 /* Notify about operation end. Note that the info could be
1378 freed before this idle happens, but the mail operation will
1380 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1383 g_object_unref (query);
1384 g_object_unref (all_folders);
1385 g_object_unref (info->account);
1386 g_object_unref (info->transport_account);
1387 g_free (info->retrieve_type);
1388 g_slice_free (UpdateAccountInfo, info);
1396 modest_mail_operation_update_account (ModestMailOperation *self,
1397 const gchar *account_name,
1398 UpdateAccountCallback callback,
1401 GThread *thread = NULL;
1402 UpdateAccountInfo *info = NULL;
1403 ModestMailOperationPrivate *priv = NULL;
1404 ModestAccountMgr *mgr = NULL;
1405 TnyStoreAccount *store_account = NULL;
1406 TnyTransportAccount *transport_account = NULL;
1408 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1409 g_return_val_if_fail (account_name, FALSE);
1411 /* Init mail operation. Set total and done to 0, and do not
1412 update them, this way the progress objects will know that
1413 we have no clue about the number of the objects */
1414 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1417 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1419 /* Get the Modest account */
1420 store_account = (TnyStoreAccount *)
1421 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1423 TNY_ACCOUNT_TYPE_STORE);
1425 /* Make sure that we have a connection, and request one
1427 * TODO: Is there some way to trigger this for every attempt to
1428 * use the network? */
1429 if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
1432 if (!store_account) {
1433 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1434 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1435 "cannot get tny store account for %s\n", account_name);
1440 /* Get the transport account, we can not do it in the thread
1441 due to some problems with dbus */
1442 transport_account = (TnyTransportAccount *)
1443 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1445 if (!transport_account) {
1446 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1447 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1448 "cannot get tny transport account for %s\n", account_name);
1452 /* Create the helper object */
1453 info = g_slice_new (UpdateAccountInfo);
1454 info->mail_op = self;
1455 info->account = store_account;
1456 info->transport_account = transport_account;
1457 info->callback = callback;
1458 info->user_data = user_data;
1460 /* Get the message size limit */
1461 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1462 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1463 if (info->max_size == 0)
1464 info->max_size = G_MAXINT;
1466 info->max_size = info->max_size * KB;
1468 /* Get per-account retrieval type */
1469 mgr = modest_runtime_get_account_mgr ();
1470 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1471 MODEST_ACCOUNT_RETRIEVE, FALSE);
1473 /* Get per-account message amount retrieval limit */
1474 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1475 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1476 if (info->retrieve_limit == 0)
1477 info->retrieve_limit = G_MAXINT;
1479 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1481 /* Set account busy */
1482 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1483 priv->account_name = g_strdup(account_name);
1485 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1490 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1492 callback (self, 0, user_data);
1493 modest_mail_operation_notify_end (self);
1497 /* ******************************************************************* */
1498 /* ************************** STORE ACTIONS ************************* */
1499 /* ******************************************************************* */
1503 modest_mail_operation_create_folder (ModestMailOperation *self,
1504 TnyFolderStore *parent,
1507 ModestMailOperationPrivate *priv;
1508 TnyFolder *new_folder = NULL;
1510 TnyList *list = tny_simple_list_new ();
1511 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1513 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1514 g_return_val_if_fail (name, NULL);
1516 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1518 /* Check for already existing folder */
1519 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1520 tny_folder_store_get_folders (parent, list, query, NULL);
1521 g_object_unref (G_OBJECT (query));
1523 if (tny_list_get_length (list) > 0) {
1524 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1525 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1526 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1527 _CS("ckdg_ib_folder_already_exists"));
1530 g_object_unref (G_OBJECT (list));
1533 if (TNY_IS_FOLDER (parent)) {
1534 /* Check folder rules */
1535 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1536 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1537 /* Set status failed and set an error */
1538 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1539 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1540 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1541 _("mail_in_ui_folder_create_error"));
1545 if (!strcmp (name, " ") || strchr (name, '/')) {
1546 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1547 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1548 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1549 _("mail_in_ui_folder_create_error"));
1553 /* Create the folder */
1554 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1555 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1557 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1560 /* Notify about operation end */
1561 modest_mail_operation_notify_end (self);
1567 modest_mail_operation_remove_folder (ModestMailOperation *self,
1569 gboolean remove_to_trash)
1571 TnyAccount *account;
1572 ModestMailOperationPrivate *priv;
1573 ModestTnyFolderRules rules;
1575 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1576 g_return_if_fail (TNY_IS_FOLDER (folder));
1578 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1580 /* Check folder rules */
1581 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1582 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1583 /* Set status failed and set an error */
1584 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1585 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1586 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1587 _("mail_in_ui_folder_delete_error"));
1591 /* Get the account */
1592 account = modest_tny_folder_get_account (folder);
1593 priv->account = g_object_ref(account);
1595 /* Delete folder or move to trash */
1596 if (remove_to_trash) {
1597 TnyFolder *trash_folder = NULL;
1598 trash_folder = modest_tny_account_get_special_folder (account,
1599 TNY_FOLDER_TYPE_TRASH);
1600 /* TODO: error_handling */
1602 modest_mail_operation_xfer_folder (self, folder,
1603 TNY_FOLDER_STORE (trash_folder),
1605 g_object_unref (trash_folder);
1608 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1610 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1611 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1614 g_object_unref (G_OBJECT (parent));
1616 g_object_unref (G_OBJECT (account));
1619 /* Notify about operation end */
1620 modest_mail_operation_notify_end (self);
1624 transfer_folder_status_cb (GObject *obj,
1628 ModestMailOperation *self;
1629 ModestMailOperationPrivate *priv;
1630 ModestMailOperationState *state;
1631 XFerMsgAsyncHelper *helper;
1633 g_return_if_fail (status != NULL);
1634 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1636 helper = (XFerMsgAsyncHelper *) user_data;
1637 g_return_if_fail (helper != NULL);
1639 self = helper->mail_op;
1640 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1642 priv->done = status->position;
1643 priv->total = status->of_total;
1645 state = modest_mail_operation_clone_state (self);
1646 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1647 gdk_threads_enter ();
1649 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1650 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1651 gdk_threads_leave ();
1653 g_slice_free (ModestMailOperationState, state);
1658 transfer_folder_cb (TnyFolder *folder,
1659 TnyFolderStore *into,
1661 TnyFolder *new_folder,
1665 XFerMsgAsyncHelper *helper;
1666 ModestMailOperation *self = NULL;
1667 ModestMailOperationPrivate *priv = NULL;
1669 helper = (XFerMsgAsyncHelper *) user_data;
1670 g_return_if_fail (helper != NULL);
1672 self = helper->mail_op;
1673 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1676 priv->error = g_error_copy (*err);
1678 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1679 } else if (cancelled) {
1680 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1681 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1682 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1683 _("Transference of %s was cancelled."),
1684 tny_folder_get_name (folder));
1687 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1690 /* Notify about operation end */
1691 modest_mail_operation_notify_end (self);
1693 /* If user defined callback function was defined, call it */
1694 if (helper->user_callback) {
1695 gdk_threads_enter ();
1696 helper->user_callback (priv->source, helper->user_data);
1697 gdk_threads_leave ();
1701 g_object_unref (helper->mail_op);
1702 g_slice_free (XFerMsgAsyncHelper, helper);
1707 * This function checks if the new name is a valid name for our local
1708 * folders account. The new name could not be the same than then name
1709 * of any of the mandatory local folders
1711 * We can not rely on tinymail because tinymail does not check the
1712 * name of the virtual folders that the account could have in the case
1713 * that we're doing a rename (because it directly calls Camel which
1714 * knows nothing about our virtual folders).
1716 * In the case of an actual copy/move (i.e. move/copy a folder between
1717 * accounts) tinymail uses the tny_folder_store_create_account which
1718 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1719 * checks the new name of the folder, so this call in that case
1720 * wouldn't be needed. *But* NOTE that if tinymail changes its
1721 * implementation (if folder transfers within the same account is no
1722 * longer implemented as a rename) this call will allow Modest to work
1725 * If the new name is not valid, this function will set the status to
1726 * failed and will set also an error in the mail operation
1729 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1730 TnyFolderStore *into,
1731 const gchar *new_name)
1733 if (TNY_IS_ACCOUNT (into) &&
1734 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1735 modest_tny_local_folders_account_extra_folder_exists (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1737 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1738 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1739 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1740 _("FIXME: folder name already in use"));
1747 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1749 TnyFolderStore *parent,
1750 gboolean delete_original,
1751 XferMsgsAsynUserCallback user_callback,
1754 ModestMailOperationPrivate *priv = NULL;
1755 ModestTnyFolderRules parent_rules = 0, rules;
1756 XFerMsgAsyncHelper *helper = NULL;
1758 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1759 g_return_if_fail (TNY_IS_FOLDER (folder));
1761 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1763 /* Get account and set it into mail_operation */
1764 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1765 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1767 /* Get folder rules */
1768 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1769 if (TNY_IS_FOLDER (parent))
1770 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1772 /* The moveable restriction is applied also to copy operation */
1773 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1774 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1775 /* Set status failed and set an error */
1776 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1777 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1778 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1779 _("mail_in_ui_folder_move_target_error"));
1781 /* Notify the queue */
1782 modest_mail_operation_notify_end (self);
1783 } else if (TNY_IS_FOLDER (parent) &&
1784 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1785 /* Set status failed and set an error */
1786 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1787 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1788 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1789 _("FIXME: parent folder does not accept new folders"));
1791 /* Notify the queue */
1792 modest_mail_operation_notify_end (self);
1796 /* Check that the new folder name is not used by any
1797 special local folder */
1798 if (new_name_valid_if_local_account (priv, parent,
1799 tny_folder_get_name (folder))) {
1800 /* Create the helper */
1801 helper = g_slice_new0 (XFerMsgAsyncHelper);
1802 helper->mail_op = g_object_ref(self);
1803 helper->dest_folder = NULL;
1804 helper->headers = NULL;
1805 helper->user_callback = user_callback;
1806 helper->user_data = user_data;
1808 /* Move/Copy folder */
1809 tny_folder_copy_async (folder,
1811 tny_folder_get_name (folder),
1814 transfer_folder_status_cb,
1817 modest_mail_operation_notify_end (self);
1823 modest_mail_operation_rename_folder (ModestMailOperation *self,
1827 ModestMailOperationPrivate *priv;
1828 ModestTnyFolderRules rules;
1829 XFerMsgAsyncHelper *helper;
1831 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1832 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1833 g_return_if_fail (name);
1835 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1837 /* Get account and set it into mail_operation */
1838 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1840 /* Check folder rules */
1841 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1842 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1843 /* Set status failed and set an error */
1844 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1845 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1846 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1847 _("FIXME: unable to rename"));
1849 /* Notify about operation end */
1850 modest_mail_operation_notify_end (self);
1851 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1852 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1853 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1854 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1855 _("FIXME: unable to rename"));
1856 /* Notify about operation end */
1857 modest_mail_operation_notify_end (self);
1859 TnyFolderStore *into;
1861 into = tny_folder_get_folder_store (folder);
1863 /* Check that the new folder name is not used by any
1864 special local folder */
1865 if (new_name_valid_if_local_account (priv, into, name)) {
1866 /* Create the helper */
1867 helper = g_slice_new0 (XFerMsgAsyncHelper);
1868 helper->mail_op = g_object_ref(self);
1869 helper->dest_folder = NULL;
1870 helper->headers = NULL;
1871 helper->user_callback = NULL;
1872 helper->user_data = NULL;
1874 /* Rename. Camel handles folder subscription/unsubscription */
1875 tny_folder_copy_async (folder, into, name, TRUE,
1877 transfer_folder_status_cb,
1880 modest_mail_operation_notify_end (self);
1882 g_object_unref (into);
1886 /* ******************************************************************* */
1887 /* ************************** MSG ACTIONS ************************* */
1888 /* ******************************************************************* */
1890 void modest_mail_operation_get_msg (ModestMailOperation *self,
1892 GetMsgAsyncUserCallback user_callback,
1895 GetMsgAsyncHelper *helper = NULL;
1897 ModestMailOperationPrivate *priv;
1899 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1900 g_return_if_fail (TNY_IS_HEADER (header));
1902 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1903 folder = tny_header_get_folder (header);
1905 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1907 /* Get message from folder */
1909 /* Get account and set it into mail_operation */
1910 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1912 helper = g_slice_new0 (GetMsgAsyncHelper);
1913 helper->mail_op = self;
1914 helper->user_callback = user_callback;
1915 helper->user_data = user_data;
1916 helper->header = g_object_ref (header);
1918 // The callback's reference so that the mail op is not
1919 // finalized until the async operation is completed even if
1920 // the user canceled the request meanwhile.
1921 g_object_ref (G_OBJECT (helper->mail_op));
1923 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1925 g_object_unref (G_OBJECT (folder));
1927 /* Set status failed and set an error */
1928 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1929 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1930 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1931 _("Error trying to get a message. No folder found for header"));
1933 /* Notify the queue */
1934 modest_mail_operation_notify_end (self);
1939 idle_get_mime_part_size_cb (gpointer userdata)
1941 GetMimePartSizeInfo *idle_info;
1943 idle_info = (GetMimePartSizeInfo *) userdata;
1945 gdk_threads_enter ();
1946 idle_info->callback (idle_info->mail_op,
1948 idle_info->userdata);
1949 gdk_threads_leave ();
1951 g_object_unref (idle_info->mail_op);
1952 g_slice_free (GetMimePartSizeInfo, idle_info);
1958 get_mime_part_size_thread (gpointer thr_user_data)
1960 GetMimePartSizeInfo *info;
1961 gchar read_buffer[GET_SIZE_BUFFER_SIZE];
1965 ModestMailOperationPrivate *priv;
1967 info = (GetMimePartSizeInfo *) thr_user_data;
1968 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1970 stream = tny_camel_mem_stream_new ();
1971 tny_mime_part_decode_to_stream (info->mime_part, stream);
1972 tny_stream_reset (stream);
1973 if (tny_stream_is_eos (stream)) {
1974 tny_stream_close (stream);
1975 stream = tny_mime_part_get_stream (info->mime_part);
1978 while (!tny_stream_is_eos (stream)) {
1979 readed_size = tny_stream_read (stream, read_buffer, GET_SIZE_BUFFER_SIZE);
1980 total += readed_size;
1983 if (info->callback) {
1984 GetMimePartSizeInfo *idle_info;
1986 idle_info = g_slice_new0 (GetMimePartSizeInfo);
1987 idle_info->mail_op = g_object_ref (info->mail_op);
1988 idle_info->size = total;
1989 idle_info->callback = info->callback;
1990 idle_info->userdata = info->userdata;
1991 g_idle_add (idle_get_mime_part_size_cb, idle_info);
1994 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1996 g_object_unref (info->mail_op);
1997 g_object_unref (stream);
1998 g_object_unref (info->mime_part);
1999 g_slice_free (GetMimePartSizeInfo, info);
2005 modest_mail_operation_get_mime_part_size (ModestMailOperation *self,
2007 GetMimePartSizeCallback user_callback,
2009 GDestroyNotify notify)
2011 GetMimePartSizeInfo *info;
2012 ModestMailOperationPrivate *priv;
2015 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2016 g_return_if_fail (TNY_IS_MIME_PART (part));
2018 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2020 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2021 info = g_slice_new0 (GetMimePartSizeInfo);
2022 info->mail_op = g_object_ref (self);
2023 info->mime_part = g_object_ref (part);
2024 info->callback = user_callback;
2025 info->userdata = user_data;
2027 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2032 get_msg_cb (TnyFolder *folder,
2038 GetMsgAsyncHelper *helper = NULL;
2039 ModestMailOperation *self = NULL;
2040 ModestMailOperationPrivate *priv = NULL;
2042 helper = (GetMsgAsyncHelper *) user_data;
2043 g_return_if_fail (helper != NULL);
2044 self = helper->mail_op;
2045 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2046 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2048 /* Check errors and cancel */
2050 priv->error = g_error_copy (*error);
2051 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2052 } else if (cancelled) {
2053 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2054 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2055 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2056 _("Error trying to refresh the contents of %s"),
2057 tny_folder_get_name (folder));
2059 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2062 /* If user defined callback function was defined, call it even
2063 if the operation failed*/
2064 if (helper->user_callback) {
2065 /* This callback is called into an iddle by tinymail,
2066 and idles are not in the main lock */
2067 gdk_threads_enter ();
2068 helper->user_callback (self, helper->header, msg, helper->user_data);
2069 gdk_threads_leave ();
2072 /* Notify about operation end */
2073 modest_mail_operation_notify_end (self);
2075 g_object_unref (helper->mail_op);
2076 g_object_unref (helper->header);
2077 g_slice_free (GetMsgAsyncHelper, helper);
2082 get_msg_status_cb (GObject *obj,
2086 GetMsgAsyncHelper *helper = NULL;
2087 ModestMailOperation *self;
2088 ModestMailOperationPrivate *priv;
2089 ModestMailOperationState *state;
2091 g_return_if_fail (status != NULL);
2092 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2094 helper = (GetMsgAsyncHelper *) user_data;
2095 g_return_if_fail (helper != NULL);
2097 self = helper->mail_op;
2098 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2103 state = modest_mail_operation_clone_state (self);
2104 state->bytes_done = status->position;
2105 state->bytes_total = status->of_total;
2106 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2107 gdk_threads_enter ();
2109 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2110 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2111 gdk_threads_leave ();
2113 g_slice_free (ModestMailOperationState, state);
2116 /****************************************************/
2118 ModestMailOperation *mail_op;
2120 GetMsgAsyncUserCallback user_callback;
2122 GDestroyNotify notify;
2126 GetMsgAsyncUserCallback user_callback;
2130 ModestMailOperation *mail_op;
2131 } NotifyGetMsgsInfo;
2135 * Used by get_msgs_full_thread to call the user_callback for each
2136 * message that has been read
2139 notify_get_msgs_full (gpointer data)
2141 NotifyGetMsgsInfo *info;
2143 info = (NotifyGetMsgsInfo *) data;
2145 /* Call the user callback. Idles are not in the main lock, so
2147 gdk_threads_enter ();
2148 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2149 gdk_threads_leave ();
2151 g_slice_free (NotifyGetMsgsInfo, info);
2157 * Used by get_msgs_full_thread to free al the thread resources and to
2158 * call the destroy function for the passed user_data
2161 get_msgs_full_destroyer (gpointer data)
2163 GetFullMsgsInfo *info;
2165 info = (GetFullMsgsInfo *) data;
2168 gdk_threads_enter ();
2169 info->notify (info->user_data);
2170 gdk_threads_leave ();
2174 g_object_unref (info->headers);
2175 g_slice_free (GetFullMsgsInfo, info);
2181 get_msgs_full_thread (gpointer thr_user_data)
2183 GetFullMsgsInfo *info;
2184 ModestMailOperationPrivate *priv = NULL;
2185 TnyIterator *iter = NULL;
2187 info = (GetFullMsgsInfo *) thr_user_data;
2188 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2190 iter = tny_list_create_iterator (info->headers);
2191 while (!tny_iterator_is_done (iter)) {
2195 header = TNY_HEADER (tny_iterator_get_current (iter));
2196 folder = tny_header_get_folder (header);
2198 /* Get message from folder */
2201 /* The callback will call it per each header */
2202 msg = tny_folder_get_msg (folder, header, &(priv->error));
2205 ModestMailOperationState *state;
2210 /* notify progress */
2211 state = modest_mail_operation_clone_state (info->mail_op);
2212 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2213 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2214 pair, (GDestroyNotify) modest_pair_free);
2216 /* The callback is the responsible for
2217 freeing the message */
2218 if (info->user_callback) {
2219 NotifyGetMsgsInfo *info_notify;
2220 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2221 info_notify->user_callback = info->user_callback;
2222 info_notify->mail_op = info->mail_op;
2223 info_notify->header = g_object_ref (header);
2224 info_notify->msg = g_object_ref (msg);
2225 info_notify->user_data = info->user_data;
2226 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2227 notify_get_msgs_full,
2230 g_object_unref (msg);
2233 /* Set status failed and set an error */
2234 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2235 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2236 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2237 "Error trying to get a message. No folder found for header");
2241 g_object_unref (header);
2243 tny_iterator_next (iter);
2246 /* Set operation status */
2247 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2248 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2250 /* Notify about operation end */
2251 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2253 /* Free thread resources. Will be called after all previous idles */
2254 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2260 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2261 TnyList *header_list,
2262 GetMsgAsyncUserCallback user_callback,
2264 GDestroyNotify notify)
2266 TnyHeader *header = NULL;
2267 TnyFolder *folder = NULL;
2269 ModestMailOperationPrivate *priv = NULL;
2270 GetFullMsgsInfo *info = NULL;
2271 gboolean size_ok = TRUE;
2273 TnyIterator *iter = NULL;
2275 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2277 /* Init mail operation */
2278 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2279 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2281 priv->total = tny_list_get_length(header_list);
2283 /* Get account and set it into mail_operation */
2284 if (tny_list_get_length (header_list) >= 1) {
2285 iter = tny_list_create_iterator (header_list);
2286 header = TNY_HEADER (tny_iterator_get_current (iter));
2288 folder = tny_header_get_folder (header);
2290 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2292 g_object_unref (folder);
2295 g_object_unref (header);
2298 if (tny_list_get_length (header_list) == 1) {
2299 g_object_unref (iter);
2304 /* Get msg size limit */
2305 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2306 MODEST_CONF_MSG_SIZE_LIMIT,
2309 g_clear_error (&(priv->error));
2310 max_size = G_MAXINT;
2312 max_size = max_size * KB;
2315 /* Check message size limits. If there is only one message
2316 always retrieve it */
2318 while (!tny_iterator_is_done (iter) && size_ok) {
2319 header = TNY_HEADER (tny_iterator_get_current (iter));
2321 if (tny_header_get_message_size (header) >= max_size)
2323 g_object_unref (header);
2326 tny_iterator_next (iter);
2328 g_object_unref (iter);
2332 /* Create the info */
2333 info = g_slice_new0 (GetFullMsgsInfo);
2334 info->mail_op = self;
2335 info->user_callback = user_callback;
2336 info->user_data = user_data;
2337 info->headers = g_object_ref (header_list);
2338 info->notify = notify;
2340 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2342 /* Set status failed and set an error */
2343 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2344 /* FIXME: the error msg is different for pop */
2345 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2346 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2347 _("emev_ni_ui_imap_msg_size_exceed_error"));
2348 /* Remove from queue and free resources */
2349 modest_mail_operation_notify_end (self);
2357 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2358 gboolean remove_to_trash /*ignored*/)
2361 ModestMailOperationPrivate *priv;
2363 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2364 g_return_if_fail (TNY_IS_HEADER (header));
2366 if (remove_to_trash)
2367 g_warning ("remove to trash is not implemented");
2369 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2370 folder = tny_header_get_folder (header);
2372 /* Get account and set it into mail_operation */
2373 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2375 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2378 tny_folder_remove_msg (folder, header, &(priv->error));
2380 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2381 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2383 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2384 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2385 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2386 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2389 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2395 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2397 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2400 g_object_unref (G_OBJECT (folder));
2402 /* Notify about operation end */
2403 modest_mail_operation_notify_end (self);
2407 transfer_msgs_status_cb (GObject *obj,
2411 XFerMsgAsyncHelper *helper = NULL;
2412 ModestMailOperation *self;
2413 ModestMailOperationPrivate *priv;
2414 ModestMailOperationState *state;
2417 g_return_if_fail (status != NULL);
2418 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2420 helper = (XFerMsgAsyncHelper *) user_data;
2421 g_return_if_fail (helper != NULL);
2423 self = helper->mail_op;
2424 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2426 priv->done = status->position;
2427 priv->total = status->of_total;
2429 state = modest_mail_operation_clone_state (self);
2430 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2431 gdk_threads_enter ();
2433 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2434 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2435 gdk_threads_leave ();
2437 g_slice_free (ModestMailOperationState, state);
2442 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2444 XFerMsgAsyncHelper *helper;
2445 ModestMailOperation *self;
2446 ModestMailOperationPrivate *priv;
2448 helper = (XFerMsgAsyncHelper *) user_data;
2449 self = helper->mail_op;
2451 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2454 priv->error = g_error_copy (*err);
2456 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2457 } else if (cancelled) {
2458 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2459 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2460 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2461 _("Error trying to refresh the contents of %s"),
2462 tny_folder_get_name (folder));
2465 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2468 /* Notify about operation end */
2469 modest_mail_operation_notify_end (self);
2471 /* If user defined callback function was defined, call it */
2472 if (helper->user_callback) {
2473 gdk_threads_enter ();
2474 helper->user_callback (priv->source, helper->user_data);
2475 gdk_threads_leave ();
2479 g_object_unref (helper->headers);
2480 g_object_unref (helper->dest_folder);
2481 g_object_unref (helper->mail_op);
2482 g_slice_free (XFerMsgAsyncHelper, helper);
2483 g_object_unref (folder);
2488 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2491 gboolean delete_original,
2492 XferMsgsAsynUserCallback user_callback,
2495 ModestMailOperationPrivate *priv = NULL;
2496 TnyIterator *iter = NULL;
2497 TnyFolder *src_folder = NULL;
2498 XFerMsgAsyncHelper *helper = NULL;
2499 TnyHeader *header = NULL;
2500 ModestTnyFolderRules rules = 0;
2501 const gchar *id1 = NULL;
2502 const gchar *id2 = NULL;
2503 gboolean same_folder = FALSE;
2505 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2506 g_return_if_fail (TNY_IS_LIST (headers));
2507 g_return_if_fail (TNY_IS_FOLDER (folder));
2509 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2512 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2514 /* Apply folder rules */
2515 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2516 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2517 /* Set status failed and set an error */
2518 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2519 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2520 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2521 _CS("ckct_ib_unable_to_paste_here"));
2522 /* Notify the queue */
2523 modest_mail_operation_notify_end (self);
2527 /* Get source folder */
2528 iter = tny_list_create_iterator (headers);
2529 header = TNY_HEADER (tny_iterator_get_current (iter));
2531 src_folder = tny_header_get_folder (header);
2532 g_object_unref (header);
2535 g_object_unref (iter);
2537 /* Check folder source and destination */
2538 id1 = tny_folder_get_id (src_folder);
2539 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2540 same_folder = !g_ascii_strcasecmp (id1, id2);
2542 /* Set status failed and set an error */
2543 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2544 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2545 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2546 _("mcen_ib_unable_to_copy_samefolder"));
2548 /* Notify the queue */
2549 modest_mail_operation_notify_end (self);
2552 g_object_unref (src_folder);
2556 /* Create the helper */
2557 helper = g_slice_new0 (XFerMsgAsyncHelper);
2558 helper->mail_op = g_object_ref(self);
2559 helper->dest_folder = g_object_ref(folder);
2560 helper->headers = g_object_ref(headers);
2561 helper->user_callback = user_callback;
2562 helper->user_data = user_data;
2564 /* Get account and set it into mail_operation */
2565 priv->account = modest_tny_folder_get_account (src_folder);
2567 /* Transfer messages */
2568 tny_folder_transfer_msgs_async (src_folder,
2573 transfer_msgs_status_cb,
2579 on_refresh_folder (TnyFolder *folder,
2584 RefreshAsyncHelper *helper = NULL;
2585 ModestMailOperation *self = NULL;
2586 ModestMailOperationPrivate *priv = NULL;
2588 helper = (RefreshAsyncHelper *) user_data;
2589 self = helper->mail_op;
2590 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2593 priv->error = g_error_copy (*error);
2594 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2599 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2600 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2601 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2602 _("Error trying to refresh the contents of %s"),
2603 tny_folder_get_name (folder));
2607 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2609 /* Call user defined callback, if it exists */
2610 if (helper->user_callback) {
2611 gdk_threads_enter ();
2612 helper->user_callback (self, folder, helper->user_data);
2613 gdk_threads_leave ();
2617 /* g_object_unref (helper->mail_op); */
2618 g_slice_free (RefreshAsyncHelper, helper);
2620 /* Notify about operation end */
2621 modest_mail_operation_notify_end (self);
2625 on_refresh_folder_status_update (GObject *obj,
2629 RefreshAsyncHelper *helper = NULL;
2630 ModestMailOperation *self = NULL;
2631 ModestMailOperationPrivate *priv = NULL;
2632 ModestMailOperationState *state;
2634 g_return_if_fail (user_data != NULL);
2635 g_return_if_fail (status != NULL);
2636 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2638 helper = (RefreshAsyncHelper *) user_data;
2639 self = helper->mail_op;
2640 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2642 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2644 priv->done = status->position;
2645 priv->total = status->of_total;
2647 state = modest_mail_operation_clone_state (self);
2648 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2649 gdk_threads_enter ();
2651 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2652 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2653 gdk_threads_leave ();
2655 g_slice_free (ModestMailOperationState, state);
2659 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2661 RefreshAsyncUserCallback user_callback,
2664 ModestMailOperationPrivate *priv = NULL;
2665 RefreshAsyncHelper *helper = NULL;
2667 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2669 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2671 /* Get account and set it into mail_operation */
2672 priv->account = modest_tny_folder_get_account (folder);
2674 /* Create the helper */
2675 helper = g_slice_new0 (RefreshAsyncHelper);
2676 helper->mail_op = g_object_ref (self);
2677 helper->user_callback = user_callback;
2678 helper->user_data = user_data;
2680 /* Refresh the folder. TODO: tinymail could issue a status
2681 updates before the callback call then this could happen. We
2682 must review the design */
2683 tny_folder_refresh_async (folder,
2685 on_refresh_folder_status_update,
2691 * It's used by the mail operation queue to notify the observers
2692 * attached to that signal that the operation finished. We need to use
2693 * that because tinymail does not give us the progress of a given
2694 * operation when it finishes (it directly calls the operation
2698 modest_mail_operation_notify_end (ModestMailOperation *self)
2700 ModestMailOperationState *state;
2701 ModestMailOperationPrivate *priv = NULL;
2703 g_return_if_fail (self);
2705 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2707 /* Set the account back to not busy */
2708 if (priv->account_name) {
2709 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2710 priv->account_name, FALSE);
2711 g_free(priv->account_name);
2712 priv->account_name = NULL;
2715 /* Notify the observers about the mail operation end */
2716 /* We do not wrapp this emission because we assume that this
2717 function is always called from within the main lock */
2718 state = modest_mail_operation_clone_state (self);
2719 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2720 g_slice_free (ModestMailOperationState, state);