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 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
1163 * show any updates unless we do that
1165 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT (priv->account))
1166 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1168 /* Get all the folders. We can do it synchronously because
1169 we're already running in a different thread than the UI */
1170 all_folders = tny_simple_list_new ();
1171 query = tny_folder_store_query_new ();
1172 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1173 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1178 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1182 iter = tny_list_create_iterator (all_folders);
1183 while (!tny_iterator_is_done (iter)) {
1184 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1186 recurse_folders (folder, query, all_folders);
1187 g_object_unref (folder);
1189 tny_iterator_next (iter);
1191 g_object_unref (G_OBJECT (iter));
1193 /* Update status and notify. We need to call the notification
1194 with a source function in order to call it from the main
1195 loop. We need that in order not to get into trouble with
1196 Gtk+. We use a timeout in order to provide more status
1197 information, because the sync tinymail call does not
1198 provide it for the moment */
1199 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1201 /* Refresh folders */
1202 num_new_headers = 0;
1203 new_headers = g_ptr_array_new ();
1204 iter = tny_list_create_iterator (all_folders);
1206 while (!tny_iterator_is_done (iter) && !priv->error &&
1207 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1209 InternalFolderObserver *observer;
1210 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1212 /* Refresh the folder */
1213 /* Our observer receives notification of new emails during folder refreshes,
1214 * so we can use observer->new_headers.
1216 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1217 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1219 /* This gets the status information (headers) from the server.
1220 * We use the blocking version, because we are already in a separate
1224 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1225 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1228 /* If the retrieve type is full messages, refresh and get the messages */
1229 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1231 iter = tny_list_create_iterator (observer->new_headers);
1232 while (!tny_iterator_is_done (iter)) {
1233 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1235 /* Apply per-message size limits */
1236 if (tny_header_get_message_size (header) < info->max_size)
1237 g_ptr_array_add (new_headers, g_object_ref (header));
1239 g_object_unref (header);
1240 tny_iterator_next (iter);
1242 g_object_unref (iter);
1244 /* We do not need to do it the first time
1245 because it's automatically done by the tree
1247 if (G_UNLIKELY (!first_time))
1248 tny_folder_poke_status (TNY_FOLDER (folder));
1250 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1251 g_object_unref (observer);
1255 g_object_unref (G_OBJECT (folder));
1258 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1260 tny_iterator_next (iter);
1263 g_object_unref (G_OBJECT (iter));
1264 g_source_remove (timeout);
1266 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1267 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1268 new_headers->len > 0) {
1272 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1274 /* Apply message count limit */
1275 /* If the number of messages exceeds the maximum, ask the
1276 * user to download them all,
1277 * as per the UI spec "Retrieval Limits" section in 4.4:
1279 if (new_headers->len > info->retrieve_limit) {
1280 /* TODO: Ask the user, instead of just
1282 * mail_nc_msg_count_limit_exceeded, with 'Get
1283 * all' and 'Newest only' buttons. */
1284 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1285 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1286 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1287 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1288 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1293 priv->total = MIN (new_headers->len, info->retrieve_limit);
1294 while (msg_num < priv->total) {
1296 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1297 TnyFolder *folder = tny_header_get_folder (header);
1298 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1299 ModestMailOperationState *state;
1303 /* We can not just use the mail operation because the
1304 values of done and total could change before the
1306 state = modest_mail_operation_clone_state (info->mail_op);
1307 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1308 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1309 pair, (GDestroyNotify) modest_pair_free);
1311 g_object_unref (msg);
1312 g_object_unref (folder);
1318 /* Get the number of new headers and free them */
1319 num_new_headers = new_headers->len;
1320 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1321 g_ptr_array_free (new_headers, FALSE);
1323 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1326 /* Perform send (if operation was not cancelled) */
1327 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1330 if (priv->account != NULL)
1331 g_object_unref (priv->account);
1332 priv->account = g_object_ref (info->transport_account);
1334 send_queue = modest_runtime_get_send_queue (info->transport_account);
1336 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1337 modest_tny_send_queue_try_to_send (send_queue);
1338 /* g_source_remove (timeout); */
1340 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1341 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1342 "cannot create a send queue for %s\n",
1343 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1344 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1347 /* Check if the operation was a success */
1349 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1351 /* Update the last updated key */
1352 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1353 set_last_updated_idle,
1354 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1355 (GDestroyNotify) g_free);
1360 if (info->callback) {
1361 UpdateAccountInfo *idle_info;
1363 /* This thread is not in the main lock */
1364 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1365 idle_info->mail_op = g_object_ref (info->mail_op);
1366 idle_info->new_headers = num_new_headers;
1367 idle_info->callback = info->callback;
1368 g_idle_add (idle_update_account_cb, idle_info);
1371 /* Notify about operation end. Note that the info could be
1372 freed before this idle happens, but the mail operation will
1374 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1377 g_object_unref (query);
1378 g_object_unref (all_folders);
1379 g_object_unref (info->account);
1380 g_object_unref (info->transport_account);
1381 g_free (info->retrieve_type);
1382 g_slice_free (UpdateAccountInfo, info);
1390 modest_mail_operation_update_account (ModestMailOperation *self,
1391 const gchar *account_name,
1392 UpdateAccountCallback callback,
1395 GThread *thread = NULL;
1396 UpdateAccountInfo *info = NULL;
1397 ModestMailOperationPrivate *priv = NULL;
1398 ModestAccountMgr *mgr = NULL;
1399 TnyStoreAccount *store_account = NULL;
1400 TnyTransportAccount *transport_account = NULL;
1402 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1403 g_return_val_if_fail (account_name, FALSE);
1405 /* Init mail operation. Set total and done to 0, and do not
1406 update them, this way the progress objects will know that
1407 we have no clue about the number of the objects */
1408 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1411 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1413 /* Get the Modest account */
1414 store_account = (TnyStoreAccount *)
1415 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1417 TNY_ACCOUNT_TYPE_STORE);
1419 /* Make sure that we have a connection, and request one
1421 * TODO: Is there some way to trigger this for every attempt to
1422 * use the network? */
1423 if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
1426 if (!store_account) {
1427 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1428 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1429 "cannot get tny store account for %s\n", account_name);
1434 /* Get the transport account, we can not do it in the thread
1435 due to some problems with dbus */
1436 transport_account = (TnyTransportAccount *)
1437 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1439 if (!transport_account) {
1440 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1441 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1442 "cannot get tny transport account for %s\n", account_name);
1446 /* Create the helper object */
1447 info = g_slice_new (UpdateAccountInfo);
1448 info->mail_op = self;
1449 info->account = store_account;
1450 info->transport_account = transport_account;
1451 info->callback = callback;
1452 info->user_data = user_data;
1454 /* Get the message size limit */
1455 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1456 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1457 if (info->max_size == 0)
1458 info->max_size = G_MAXINT;
1460 info->max_size = info->max_size * KB;
1462 /* Get per-account retrieval type */
1463 mgr = modest_runtime_get_account_mgr ();
1464 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1465 MODEST_ACCOUNT_RETRIEVE, FALSE);
1467 /* Get per-account message amount retrieval limit */
1468 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1469 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1470 if (info->retrieve_limit == 0)
1471 info->retrieve_limit = G_MAXINT;
1473 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1475 /* Set account busy */
1476 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1477 priv->account_name = g_strdup(account_name);
1479 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1484 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1486 callback (self, 0, user_data);
1487 modest_mail_operation_notify_end (self);
1491 /* ******************************************************************* */
1492 /* ************************** STORE ACTIONS ************************* */
1493 /* ******************************************************************* */
1497 modest_mail_operation_create_folder (ModestMailOperation *self,
1498 TnyFolderStore *parent,
1501 ModestMailOperationPrivate *priv;
1502 TnyFolder *new_folder = NULL;
1504 TnyList *list = tny_simple_list_new ();
1505 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1507 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1508 g_return_val_if_fail (name, NULL);
1510 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1512 /* Check for already existing folder */
1513 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1514 tny_folder_store_get_folders (parent, list, query, NULL);
1515 g_object_unref (G_OBJECT (query));
1517 if (tny_list_get_length (list) > 0) {
1518 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1519 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1520 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1521 _CS("ckdg_ib_folder_already_exists"));
1524 g_object_unref (G_OBJECT (list));
1527 if (TNY_IS_FOLDER (parent)) {
1528 /* Check folder rules */
1529 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1530 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1531 /* Set status failed and set an error */
1532 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1533 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1534 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1535 _("mail_in_ui_folder_create_error"));
1539 if (!strcmp (name, " ") || strchr (name, '/')) {
1540 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1541 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1542 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1543 _("mail_in_ui_folder_create_error"));
1547 /* Create the folder */
1548 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1549 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1551 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1554 /* Notify about operation end */
1555 modest_mail_operation_notify_end (self);
1561 modest_mail_operation_remove_folder (ModestMailOperation *self,
1563 gboolean remove_to_trash)
1565 TnyAccount *account;
1566 ModestMailOperationPrivate *priv;
1567 ModestTnyFolderRules rules;
1569 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1570 g_return_if_fail (TNY_IS_FOLDER (folder));
1572 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1574 /* Check folder rules */
1575 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1576 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1577 /* Set status failed and set an error */
1578 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1579 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1580 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1581 _("mail_in_ui_folder_delete_error"));
1585 /* Get the account */
1586 account = modest_tny_folder_get_account (folder);
1587 priv->account = g_object_ref(account);
1589 /* Delete folder or move to trash */
1590 if (remove_to_trash) {
1591 TnyFolder *trash_folder = NULL;
1592 trash_folder = modest_tny_account_get_special_folder (account,
1593 TNY_FOLDER_TYPE_TRASH);
1594 /* TODO: error_handling */
1596 modest_mail_operation_xfer_folder (self, folder,
1597 TNY_FOLDER_STORE (trash_folder),
1599 g_object_unref (trash_folder);
1602 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1604 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1605 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1608 g_object_unref (G_OBJECT (parent));
1610 g_object_unref (G_OBJECT (account));
1613 /* Notify about operation end */
1614 modest_mail_operation_notify_end (self);
1618 transfer_folder_status_cb (GObject *obj,
1622 ModestMailOperation *self;
1623 ModestMailOperationPrivate *priv;
1624 ModestMailOperationState *state;
1625 XFerMsgAsyncHelper *helper;
1627 g_return_if_fail (status != NULL);
1628 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1630 helper = (XFerMsgAsyncHelper *) user_data;
1631 g_return_if_fail (helper != NULL);
1633 self = helper->mail_op;
1634 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1636 priv->done = status->position;
1637 priv->total = status->of_total;
1639 state = modest_mail_operation_clone_state (self);
1640 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1641 gdk_threads_enter ();
1643 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1644 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1645 gdk_threads_leave ();
1647 g_slice_free (ModestMailOperationState, state);
1652 transfer_folder_cb (TnyFolder *folder,
1653 TnyFolderStore *into,
1655 TnyFolder *new_folder,
1659 XFerMsgAsyncHelper *helper;
1660 ModestMailOperation *self = NULL;
1661 ModestMailOperationPrivate *priv = NULL;
1663 helper = (XFerMsgAsyncHelper *) user_data;
1664 g_return_if_fail (helper != NULL);
1666 self = helper->mail_op;
1667 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1670 priv->error = g_error_copy (*err);
1672 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1673 } else if (cancelled) {
1674 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1675 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1676 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1677 _("Transference of %s was cancelled."),
1678 tny_folder_get_name (folder));
1681 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1684 /* Notify about operation end */
1685 modest_mail_operation_notify_end (self);
1687 /* If user defined callback function was defined, call it */
1688 if (helper->user_callback) {
1689 gdk_threads_enter ();
1690 helper->user_callback (priv->source, helper->user_data);
1691 gdk_threads_leave ();
1695 g_object_unref (helper->mail_op);
1696 g_slice_free (XFerMsgAsyncHelper, helper);
1701 * This function checks if the new name is a valid name for our local
1702 * folders account. The new name could not be the same than then name
1703 * of any of the mandatory local folders
1705 * We can not rely on tinymail because tinymail does not check the
1706 * name of the virtual folders that the account could have in the case
1707 * that we're doing a rename (because it directly calls Camel which
1708 * knows nothing about our virtual folders).
1710 * In the case of an actual copy/move (i.e. move/copy a folder between
1711 * accounts) tinymail uses the tny_folder_store_create_account which
1712 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1713 * checks the new name of the folder, so this call in that case
1714 * wouldn't be needed. *But* NOTE that if tinymail changes its
1715 * implementation (if folder transfers within the same account is no
1716 * longer implemented as a rename) this call will allow Modest to work
1719 * If the new name is not valid, this function will set the status to
1720 * failed and will set also an error in the mail operation
1723 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1724 TnyFolderStore *into,
1725 const gchar *new_name)
1727 if (TNY_IS_ACCOUNT (into) &&
1728 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1729 modest_tny_local_folders_account_extra_folder_exists (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1731 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1732 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1733 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1734 _("FIXME: folder name already in use"));
1741 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1743 TnyFolderStore *parent,
1744 gboolean delete_original,
1745 XferMsgsAsynUserCallback user_callback,
1748 ModestMailOperationPrivate *priv = NULL;
1749 ModestTnyFolderRules parent_rules = 0, rules;
1750 XFerMsgAsyncHelper *helper = NULL;
1752 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1753 g_return_if_fail (TNY_IS_FOLDER (folder));
1755 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1757 /* Get account and set it into mail_operation */
1758 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1759 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1761 /* Get folder rules */
1762 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1763 if (TNY_IS_FOLDER (parent))
1764 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1766 /* The moveable restriction is applied also to copy operation */
1767 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1768 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1769 /* Set status failed and set an error */
1770 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1771 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1772 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1773 _("mail_in_ui_folder_move_target_error"));
1775 /* Notify the queue */
1776 modest_mail_operation_notify_end (self);
1777 } else if (TNY_IS_FOLDER (parent) &&
1778 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1779 /* Set status failed and set an error */
1780 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1781 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1782 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1783 _("FIXME: parent folder does not accept new folders"));
1785 /* Notify the queue */
1786 modest_mail_operation_notify_end (self);
1790 /* Check that the new folder name is not used by any
1791 special local folder */
1792 if (new_name_valid_if_local_account (priv, parent,
1793 tny_folder_get_name (folder))) {
1794 /* Create the helper */
1795 helper = g_slice_new0 (XFerMsgAsyncHelper);
1796 helper->mail_op = g_object_ref(self);
1797 helper->dest_folder = NULL;
1798 helper->headers = NULL;
1799 helper->user_callback = user_callback;
1800 helper->user_data = user_data;
1802 /* Move/Copy folder */
1803 tny_folder_copy_async (folder,
1805 tny_folder_get_name (folder),
1808 transfer_folder_status_cb,
1811 modest_mail_operation_notify_end (self);
1817 modest_mail_operation_rename_folder (ModestMailOperation *self,
1821 ModestMailOperationPrivate *priv;
1822 ModestTnyFolderRules rules;
1823 XFerMsgAsyncHelper *helper;
1825 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1826 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1827 g_return_if_fail (name);
1829 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1831 /* Get account and set it into mail_operation */
1832 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1834 /* Check folder rules */
1835 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1836 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1837 /* Set status failed and set an error */
1838 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1839 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1840 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1841 _("FIXME: unable to rename"));
1843 /* Notify about operation end */
1844 modest_mail_operation_notify_end (self);
1845 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1846 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1847 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1848 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1849 _("FIXME: unable to rename"));
1850 /* Notify about operation end */
1851 modest_mail_operation_notify_end (self);
1853 TnyFolderStore *into;
1855 into = tny_folder_get_folder_store (folder);
1857 /* Check that the new folder name is not used by any
1858 special local folder */
1859 if (new_name_valid_if_local_account (priv, into, name)) {
1860 /* Create the helper */
1861 helper = g_slice_new0 (XFerMsgAsyncHelper);
1862 helper->mail_op = g_object_ref(self);
1863 helper->dest_folder = NULL;
1864 helper->headers = NULL;
1865 helper->user_callback = NULL;
1866 helper->user_data = NULL;
1868 /* Rename. Camel handles folder subscription/unsubscription */
1869 tny_folder_copy_async (folder, into, name, TRUE,
1871 transfer_folder_status_cb,
1874 modest_mail_operation_notify_end (self);
1876 g_object_unref (into);
1880 /* ******************************************************************* */
1881 /* ************************** MSG ACTIONS ************************* */
1882 /* ******************************************************************* */
1884 void modest_mail_operation_get_msg (ModestMailOperation *self,
1886 GetMsgAsyncUserCallback user_callback,
1889 GetMsgAsyncHelper *helper = NULL;
1891 ModestMailOperationPrivate *priv;
1893 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1894 g_return_if_fail (TNY_IS_HEADER (header));
1896 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1897 folder = tny_header_get_folder (header);
1899 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1901 /* Get message from folder */
1903 /* Get account and set it into mail_operation */
1904 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1906 helper = g_slice_new0 (GetMsgAsyncHelper);
1907 helper->mail_op = self;
1908 helper->user_callback = user_callback;
1909 helper->user_data = user_data;
1910 helper->header = g_object_ref (header);
1912 // The callback's reference so that the mail op is not
1913 // finalized until the async operation is completed even if
1914 // the user canceled the request meanwhile.
1915 g_object_ref (G_OBJECT (helper->mail_op));
1917 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1919 g_object_unref (G_OBJECT (folder));
1921 /* Set status failed and set an error */
1922 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1923 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1924 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1925 _("Error trying to get a message. No folder found for header"));
1927 /* Notify the queue */
1928 modest_mail_operation_notify_end (self);
1933 idle_get_mime_part_size_cb (gpointer userdata)
1935 GetMimePartSizeInfo *idle_info;
1937 idle_info = (GetMimePartSizeInfo *) userdata;
1939 gdk_threads_enter ();
1940 idle_info->callback (idle_info->mail_op,
1942 idle_info->userdata);
1943 gdk_threads_leave ();
1945 g_object_unref (idle_info->mail_op);
1946 g_slice_free (GetMimePartSizeInfo, idle_info);
1952 get_mime_part_size_thread (gpointer thr_user_data)
1954 GetMimePartSizeInfo *info;
1955 gchar read_buffer[GET_SIZE_BUFFER_SIZE];
1959 ModestMailOperationPrivate *priv;
1961 info = (GetMimePartSizeInfo *) thr_user_data;
1962 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1964 stream = tny_camel_mem_stream_new ();
1965 tny_mime_part_decode_to_stream (info->mime_part, stream);
1966 tny_stream_reset (stream);
1967 if (tny_stream_is_eos (stream)) {
1968 tny_stream_close (stream);
1969 stream = tny_mime_part_get_stream (info->mime_part);
1972 while (!tny_stream_is_eos (stream)) {
1973 readed_size = tny_stream_read (stream, read_buffer, GET_SIZE_BUFFER_SIZE);
1974 total += readed_size;
1977 if (info->callback) {
1978 GetMimePartSizeInfo *idle_info;
1980 idle_info = g_slice_new0 (GetMimePartSizeInfo);
1981 idle_info->mail_op = g_object_ref (info->mail_op);
1982 idle_info->size = total;
1983 idle_info->callback = info->callback;
1984 idle_info->userdata = info->userdata;
1985 g_idle_add (idle_get_mime_part_size_cb, idle_info);
1988 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1990 g_object_unref (info->mail_op);
1991 g_object_unref (stream);
1992 g_object_unref (info->mime_part);
1993 g_slice_free (GetMimePartSizeInfo, info);
1999 modest_mail_operation_get_mime_part_size (ModestMailOperation *self,
2001 GetMimePartSizeCallback user_callback,
2003 GDestroyNotify notify)
2005 GetMimePartSizeInfo *info;
2006 ModestMailOperationPrivate *priv;
2009 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2010 g_return_if_fail (TNY_IS_MIME_PART (part));
2012 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2014 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2015 info = g_slice_new0 (GetMimePartSizeInfo);
2016 info->mail_op = g_object_ref (self);
2017 info->mime_part = g_object_ref (part);
2018 info->callback = user_callback;
2019 info->userdata = user_data;
2021 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2026 get_msg_cb (TnyFolder *folder,
2032 GetMsgAsyncHelper *helper = NULL;
2033 ModestMailOperation *self = NULL;
2034 ModestMailOperationPrivate *priv = NULL;
2036 helper = (GetMsgAsyncHelper *) user_data;
2037 g_return_if_fail (helper != NULL);
2038 self = helper->mail_op;
2039 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2040 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2042 /* Check errors and cancel */
2044 priv->error = g_error_copy (*error);
2045 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2046 } else if (cancelled) {
2047 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2048 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2049 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2050 _("Error trying to refresh the contents of %s"),
2051 tny_folder_get_name (folder));
2053 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2056 /* If user defined callback function was defined, call it even
2057 if the operation failed*/
2058 if (helper->user_callback) {
2059 /* This callback is called into an iddle by tinymail,
2060 and idles are not in the main lock */
2061 gdk_threads_enter ();
2062 helper->user_callback (self, helper->header, msg, helper->user_data);
2063 gdk_threads_leave ();
2066 /* Notify about operation end */
2067 modest_mail_operation_notify_end (self);
2069 g_object_unref (helper->mail_op);
2070 g_object_unref (helper->header);
2071 g_slice_free (GetMsgAsyncHelper, helper);
2076 get_msg_status_cb (GObject *obj,
2080 GetMsgAsyncHelper *helper = NULL;
2081 ModestMailOperation *self;
2082 ModestMailOperationPrivate *priv;
2083 ModestMailOperationState *state;
2085 g_return_if_fail (status != NULL);
2086 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2088 helper = (GetMsgAsyncHelper *) user_data;
2089 g_return_if_fail (helper != NULL);
2091 self = helper->mail_op;
2092 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2097 state = modest_mail_operation_clone_state (self);
2098 state->bytes_done = status->position;
2099 state->bytes_total = status->of_total;
2100 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2101 gdk_threads_enter ();
2103 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2104 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2105 gdk_threads_leave ();
2107 g_slice_free (ModestMailOperationState, state);
2110 /****************************************************/
2112 ModestMailOperation *mail_op;
2114 GetMsgAsyncUserCallback user_callback;
2116 GDestroyNotify notify;
2120 GetMsgAsyncUserCallback user_callback;
2124 ModestMailOperation *mail_op;
2125 } NotifyGetMsgsInfo;
2129 * Used by get_msgs_full_thread to call the user_callback for each
2130 * message that has been read
2133 notify_get_msgs_full (gpointer data)
2135 NotifyGetMsgsInfo *info;
2137 info = (NotifyGetMsgsInfo *) data;
2139 /* Call the user callback. Idles are not in the main lock, so
2141 gdk_threads_enter ();
2142 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2143 gdk_threads_leave ();
2145 g_slice_free (NotifyGetMsgsInfo, info);
2151 * Used by get_msgs_full_thread to free al the thread resources and to
2152 * call the destroy function for the passed user_data
2155 get_msgs_full_destroyer (gpointer data)
2157 GetFullMsgsInfo *info;
2159 info = (GetFullMsgsInfo *) data;
2162 gdk_threads_enter ();
2163 info->notify (info->user_data);
2164 gdk_threads_leave ();
2168 g_object_unref (info->headers);
2169 g_slice_free (GetFullMsgsInfo, info);
2175 get_msgs_full_thread (gpointer thr_user_data)
2177 GetFullMsgsInfo *info;
2178 ModestMailOperationPrivate *priv = NULL;
2179 TnyIterator *iter = NULL;
2181 info = (GetFullMsgsInfo *) thr_user_data;
2182 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2184 iter = tny_list_create_iterator (info->headers);
2185 while (!tny_iterator_is_done (iter)) {
2189 header = TNY_HEADER (tny_iterator_get_current (iter));
2190 folder = tny_header_get_folder (header);
2192 /* Get message from folder */
2195 /* The callback will call it per each header */
2196 msg = tny_folder_get_msg (folder, header, &(priv->error));
2199 ModestMailOperationState *state;
2204 /* notify progress */
2205 state = modest_mail_operation_clone_state (info->mail_op);
2206 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2207 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2208 pair, (GDestroyNotify) modest_pair_free);
2210 /* The callback is the responsible for
2211 freeing the message */
2212 if (info->user_callback) {
2213 NotifyGetMsgsInfo *info_notify;
2214 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2215 info_notify->user_callback = info->user_callback;
2216 info_notify->mail_op = info->mail_op;
2217 info_notify->header = g_object_ref (header);
2218 info_notify->msg = g_object_ref (msg);
2219 info_notify->user_data = info->user_data;
2220 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2221 notify_get_msgs_full,
2224 g_object_unref (msg);
2227 /* Set status failed and set an error */
2228 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2229 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2230 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2231 "Error trying to get a message. No folder found for header");
2235 g_object_unref (header);
2237 tny_iterator_next (iter);
2240 /* Set operation status */
2241 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2242 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2244 /* Notify about operation end */
2245 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2247 /* Free thread resources. Will be called after all previous idles */
2248 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2254 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2255 TnyList *header_list,
2256 GetMsgAsyncUserCallback user_callback,
2258 GDestroyNotify notify)
2260 TnyHeader *header = NULL;
2261 TnyFolder *folder = NULL;
2263 ModestMailOperationPrivate *priv = NULL;
2264 GetFullMsgsInfo *info = NULL;
2265 gboolean size_ok = TRUE;
2267 TnyIterator *iter = NULL;
2269 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2271 /* Init mail operation */
2272 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2273 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2275 priv->total = tny_list_get_length(header_list);
2277 /* Get account and set it into mail_operation */
2278 if (tny_list_get_length (header_list) >= 1) {
2279 iter = tny_list_create_iterator (header_list);
2280 header = TNY_HEADER (tny_iterator_get_current (iter));
2282 folder = tny_header_get_folder (header);
2284 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2286 g_object_unref (folder);
2289 g_object_unref (header);
2292 if (tny_list_get_length (header_list) == 1) {
2293 g_object_unref (iter);
2298 /* Get msg size limit */
2299 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2300 MODEST_CONF_MSG_SIZE_LIMIT,
2303 g_clear_error (&(priv->error));
2304 max_size = G_MAXINT;
2306 max_size = max_size * KB;
2309 /* Check message size limits. If there is only one message
2310 always retrieve it */
2312 while (!tny_iterator_is_done (iter) && size_ok) {
2313 header = TNY_HEADER (tny_iterator_get_current (iter));
2315 if (tny_header_get_message_size (header) >= max_size)
2317 g_object_unref (header);
2320 tny_iterator_next (iter);
2322 g_object_unref (iter);
2326 /* Create the info */
2327 info = g_slice_new0 (GetFullMsgsInfo);
2328 info->mail_op = self;
2329 info->user_callback = user_callback;
2330 info->user_data = user_data;
2331 info->headers = g_object_ref (header_list);
2332 info->notify = notify;
2334 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2336 /* Set status failed and set an error */
2337 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2338 /* FIXME: the error msg is different for pop */
2339 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2340 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2341 _("emev_ni_ui_imap_msg_size_exceed_error"));
2342 /* Remove from queue and free resources */
2343 modest_mail_operation_notify_end (self);
2351 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2352 gboolean remove_to_trash /*ignored*/)
2355 ModestMailOperationPrivate *priv;
2357 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2358 g_return_if_fail (TNY_IS_HEADER (header));
2360 if (remove_to_trash)
2361 g_warning ("remove to trash is not implemented");
2363 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2364 folder = tny_header_get_folder (header);
2366 /* Get account and set it into mail_operation */
2367 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2369 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2372 tny_folder_remove_msg (folder, header, &(priv->error));
2374 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2375 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2377 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2378 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2379 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2380 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2383 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2389 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2391 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2394 g_object_unref (G_OBJECT (folder));
2396 /* Notify about operation end */
2397 modest_mail_operation_notify_end (self);
2401 transfer_msgs_status_cb (GObject *obj,
2405 XFerMsgAsyncHelper *helper = NULL;
2406 ModestMailOperation *self;
2407 ModestMailOperationPrivate *priv;
2408 ModestMailOperationState *state;
2411 g_return_if_fail (status != NULL);
2412 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2414 helper = (XFerMsgAsyncHelper *) user_data;
2415 g_return_if_fail (helper != NULL);
2417 self = helper->mail_op;
2418 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2420 priv->done = status->position;
2421 priv->total = status->of_total;
2423 state = modest_mail_operation_clone_state (self);
2424 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2425 gdk_threads_enter ();
2427 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2428 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2429 gdk_threads_leave ();
2431 g_slice_free (ModestMailOperationState, state);
2436 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2438 XFerMsgAsyncHelper *helper;
2439 ModestMailOperation *self;
2440 ModestMailOperationPrivate *priv;
2442 helper = (XFerMsgAsyncHelper *) user_data;
2443 self = helper->mail_op;
2445 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2448 priv->error = g_error_copy (*err);
2450 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2451 } else if (cancelled) {
2452 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2453 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2454 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2455 _("Error trying to refresh the contents of %s"),
2456 tny_folder_get_name (folder));
2459 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2462 /* Notify about operation end */
2463 modest_mail_operation_notify_end (self);
2465 /* If user defined callback function was defined, call it */
2466 if (helper->user_callback) {
2467 gdk_threads_enter ();
2468 helper->user_callback (priv->source, helper->user_data);
2469 gdk_threads_leave ();
2473 g_object_unref (helper->headers);
2474 g_object_unref (helper->dest_folder);
2475 g_object_unref (helper->mail_op);
2476 g_slice_free (XFerMsgAsyncHelper, helper);
2477 g_object_unref (folder);
2482 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2485 gboolean delete_original,
2486 XferMsgsAsynUserCallback user_callback,
2489 ModestMailOperationPrivate *priv = NULL;
2490 TnyIterator *iter = NULL;
2491 TnyFolder *src_folder = NULL;
2492 XFerMsgAsyncHelper *helper = NULL;
2493 TnyHeader *header = NULL;
2494 ModestTnyFolderRules rules = 0;
2495 const gchar *id1 = NULL;
2496 const gchar *id2 = NULL;
2497 gboolean same_folder = FALSE;
2499 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2500 g_return_if_fail (TNY_IS_LIST (headers));
2501 g_return_if_fail (TNY_IS_FOLDER (folder));
2503 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2506 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2508 /* Apply folder rules */
2509 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2510 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2511 /* Set status failed and set an error */
2512 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2513 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2514 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2515 _CS("ckct_ib_unable_to_paste_here"));
2516 /* Notify the queue */
2517 modest_mail_operation_notify_end (self);
2521 /* Get source folder */
2522 iter = tny_list_create_iterator (headers);
2523 header = TNY_HEADER (tny_iterator_get_current (iter));
2525 src_folder = tny_header_get_folder (header);
2526 g_object_unref (header);
2529 g_object_unref (iter);
2531 /* Check folder source and destination */
2532 id1 = tny_folder_get_id (src_folder);
2533 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2534 same_folder = !g_ascii_strcasecmp (id1, id2);
2536 /* Set status failed and set an error */
2537 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2538 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2539 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2540 _("mcen_ib_unable_to_copy_samefolder"));
2542 /* Notify the queue */
2543 modest_mail_operation_notify_end (self);
2546 g_object_unref (src_folder);
2550 /* Create the helper */
2551 helper = g_slice_new0 (XFerMsgAsyncHelper);
2552 helper->mail_op = g_object_ref(self);
2553 helper->dest_folder = g_object_ref(folder);
2554 helper->headers = g_object_ref(headers);
2555 helper->user_callback = user_callback;
2556 helper->user_data = user_data;
2558 /* Get account and set it into mail_operation */
2559 priv->account = modest_tny_folder_get_account (src_folder);
2561 /* Transfer messages */
2562 tny_folder_transfer_msgs_async (src_folder,
2567 transfer_msgs_status_cb,
2573 on_refresh_folder (TnyFolder *folder,
2578 RefreshAsyncHelper *helper = NULL;
2579 ModestMailOperation *self = NULL;
2580 ModestMailOperationPrivate *priv = NULL;
2582 helper = (RefreshAsyncHelper *) user_data;
2583 self = helper->mail_op;
2584 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2587 priv->error = g_error_copy (*error);
2588 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2593 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2594 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2595 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2596 _("Error trying to refresh the contents of %s"),
2597 tny_folder_get_name (folder));
2601 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2603 /* Call user defined callback, if it exists */
2604 if (helper->user_callback) {
2605 gdk_threads_enter ();
2606 helper->user_callback (self, folder, helper->user_data);
2607 gdk_threads_leave ();
2611 /* g_object_unref (helper->mail_op); */
2612 g_slice_free (RefreshAsyncHelper, helper);
2614 /* Notify about operation end */
2615 modest_mail_operation_notify_end (self);
2619 on_refresh_folder_status_update (GObject *obj,
2623 RefreshAsyncHelper *helper = NULL;
2624 ModestMailOperation *self = NULL;
2625 ModestMailOperationPrivate *priv = NULL;
2626 ModestMailOperationState *state;
2628 g_return_if_fail (user_data != NULL);
2629 g_return_if_fail (status != NULL);
2630 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2632 helper = (RefreshAsyncHelper *) user_data;
2633 self = helper->mail_op;
2634 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2636 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2638 priv->done = status->position;
2639 priv->total = status->of_total;
2641 state = modest_mail_operation_clone_state (self);
2642 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2643 gdk_threads_enter ();
2645 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2646 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2647 gdk_threads_leave ();
2649 g_slice_free (ModestMailOperationState, state);
2653 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2655 RefreshAsyncUserCallback user_callback,
2658 ModestMailOperationPrivate *priv = NULL;
2659 RefreshAsyncHelper *helper = NULL;
2661 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2663 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2665 /* Get account and set it into mail_operation */
2666 priv->account = modest_tny_folder_get_account (folder);
2668 /* Create the helper */
2669 helper = g_slice_new0 (RefreshAsyncHelper);
2670 helper->mail_op = g_object_ref (self);
2671 helper->user_callback = user_callback;
2672 helper->user_data = user_data;
2674 /* Refresh the folder. TODO: tinymail could issue a status
2675 updates before the callback call then this could happen. We
2676 must review the design */
2677 tny_folder_refresh_async (folder,
2679 on_refresh_folder_status_update,
2685 * It's used by the mail operation queue to notify the observers
2686 * attached to that signal that the operation finished. We need to use
2687 * that because tinymail does not give us the progress of a given
2688 * operation when it finishes (it directly calls the operation
2692 modest_mail_operation_notify_end (ModestMailOperation *self)
2694 ModestMailOperationState *state;
2695 ModestMailOperationPrivate *priv = NULL;
2697 g_return_if_fail (self);
2699 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2701 /* Set the account back to not busy */
2702 if (priv->account_name) {
2703 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2704 priv->account_name, FALSE);
2705 g_free(priv->account_name);
2706 priv->account_name = NULL;
2709 /* Notify the observers about the mail operation end */
2710 /* We do not wrapp this emission because we assume that this
2711 function is always called from within the main lock */
2712 state = modest_mail_operation_clone_state (self);
2713 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2714 g_slice_free (ModestMailOperationState, state);