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
63 /* 'private'/'protected' functions */
64 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
65 static void modest_mail_operation_init (ModestMailOperation *obj);
66 static void modest_mail_operation_finalize (GObject *obj);
68 static void get_msg_cb (TnyFolder *folder,
74 static void get_msg_status_cb (GObject *obj,
78 static void modest_mail_operation_notify_end (ModestMailOperation *self);
80 static gboolean did_a_cancel = FALSE;
82 enum _ModestMailOperationSignals
84 PROGRESS_CHANGED_SIGNAL,
89 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
90 struct _ModestMailOperationPrivate {
97 ErrorCheckingUserCallback error_checking;
98 gpointer error_checking_user_data;
99 ModestMailOperationStatus status;
100 ModestMailOperationTypeOperation op_type;
103 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
104 MODEST_TYPE_MAIL_OPERATION, \
105 ModestMailOperationPrivate))
107 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
108 priv->status = new_status;\
111 typedef struct _GetMsgAsyncHelper {
112 ModestMailOperation *mail_op;
114 GetMsgAsyncUserCallback user_callback;
118 typedef struct _RefreshAsyncHelper {
119 ModestMailOperation *mail_op;
120 RefreshAsyncUserCallback user_callback;
122 } RefreshAsyncHelper;
124 typedef struct _XFerMsgAsyncHelper
126 ModestMailOperation *mail_op;
128 TnyFolder *dest_folder;
129 XferMsgsAsynUserCallback user_callback;
131 } XFerMsgAsyncHelper;
133 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
137 static void modest_mail_operation_create_msg (ModestMailOperation *self,
138 const gchar *from, const gchar *to,
139 const gchar *cc, const gchar *bcc,
140 const gchar *subject, const gchar *plain_body,
141 const gchar *html_body, const GList *attachments_list,
142 TnyHeaderFlags priority_flags,
143 ModestMailOperationCreateMsgCallback callback,
146 static gboolean idle_notify_queue (gpointer data);
149 ModestMailOperation *mail_op;
157 GList *attachments_list;
158 TnyHeaderFlags priority_flags;
159 ModestMailOperationCreateMsgCallback callback;
165 ModestMailOperation *mail_op;
167 ModestMailOperationCreateMsgCallback callback;
172 static GObjectClass *parent_class = NULL;
174 static guint signals[NUM_SIGNALS] = {0};
177 modest_mail_operation_get_type (void)
179 static GType my_type = 0;
181 static const GTypeInfo my_info = {
182 sizeof(ModestMailOperationClass),
183 NULL, /* base init */
184 NULL, /* base finalize */
185 (GClassInitFunc) modest_mail_operation_class_init,
186 NULL, /* class finalize */
187 NULL, /* class data */
188 sizeof(ModestMailOperation),
190 (GInstanceInitFunc) modest_mail_operation_init,
193 my_type = g_type_register_static (G_TYPE_OBJECT,
194 "ModestMailOperation",
201 modest_mail_operation_class_init (ModestMailOperationClass *klass)
203 GObjectClass *gobject_class;
204 gobject_class = (GObjectClass*) klass;
206 parent_class = g_type_class_peek_parent (klass);
207 gobject_class->finalize = modest_mail_operation_finalize;
209 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
212 * ModestMailOperation::progress-changed
213 * @self: the #MailOperation that emits the signal
214 * @user_data: user data set when the signal handler was connected
216 * Emitted when the progress of a mail operation changes
218 signals[PROGRESS_CHANGED_SIGNAL] =
219 g_signal_new ("progress-changed",
220 G_TYPE_FROM_CLASS (gobject_class),
222 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
224 g_cclosure_marshal_VOID__POINTER,
225 G_TYPE_NONE, 1, G_TYPE_POINTER);
230 modest_mail_operation_init (ModestMailOperation *obj)
232 ModestMailOperationPrivate *priv;
234 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
236 priv->account = NULL;
237 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
238 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
243 priv->error_checking = NULL;
244 priv->error_checking_user_data = NULL;
248 modest_mail_operation_finalize (GObject *obj)
250 ModestMailOperationPrivate *priv;
252 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
257 g_error_free (priv->error);
261 g_object_unref (priv->source);
265 g_object_unref (priv->account);
266 priv->account = NULL;
270 G_OBJECT_CLASS(parent_class)->finalize (obj);
274 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
277 ModestMailOperation *obj;
278 ModestMailOperationPrivate *priv;
280 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
281 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
283 priv->op_type = op_type;
285 priv->source = g_object_ref(source);
291 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
293 ErrorCheckingUserCallback error_handler,
296 ModestMailOperation *obj;
297 ModestMailOperationPrivate *priv;
299 obj = modest_mail_operation_new (op_type, source);
300 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
302 g_return_val_if_fail (error_handler != NULL, obj);
303 priv->error_checking = error_handler;
309 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
311 ModestMailOperationPrivate *priv;
313 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
314 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
316 if (priv->error_checking != NULL)
317 priv->error_checking (self, priv->error_checking_user_data);
321 ModestMailOperationTypeOperation
322 modest_mail_operation_get_type_operation (ModestMailOperation *self)
324 ModestMailOperationPrivate *priv;
326 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
328 return priv->op_type;
332 modest_mail_operation_is_mine (ModestMailOperation *self,
335 ModestMailOperationPrivate *priv;
337 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
338 if (priv->source == NULL) return FALSE;
340 return priv->source == me;
344 modest_mail_operation_get_source (ModestMailOperation *self)
346 ModestMailOperationPrivate *priv;
348 g_return_val_if_fail (self, NULL);
350 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
352 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
356 return g_object_ref (priv->source);
359 ModestMailOperationStatus
360 modest_mail_operation_get_status (ModestMailOperation *self)
362 ModestMailOperationPrivate *priv;
364 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
365 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
366 MODEST_MAIL_OPERATION_STATUS_INVALID);
368 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
370 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
371 return MODEST_MAIL_OPERATION_STATUS_INVALID;
378 modest_mail_operation_get_error (ModestMailOperation *self)
380 ModestMailOperationPrivate *priv;
382 g_return_val_if_fail (self, NULL);
383 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
385 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
388 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
396 modest_mail_operation_cancel (ModestMailOperation *self)
398 ModestMailOperationPrivate *priv;
400 if (!MODEST_IS_MAIL_OPERATION (self)) {
401 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
405 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
407 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
414 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
416 /* This emits progress-changed on which the mail operation queue is
417 * listening, so the mail operation is correctly removed from the
418 * queue without further explicit calls. */
419 modest_mail_operation_notify_end (self);
425 modest_mail_operation_get_task_done (ModestMailOperation *self)
427 ModestMailOperationPrivate *priv;
429 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
431 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
436 modest_mail_operation_get_task_total (ModestMailOperation *self)
438 ModestMailOperationPrivate *priv;
440 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
442 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
447 modest_mail_operation_is_finished (ModestMailOperation *self)
449 ModestMailOperationPrivate *priv;
450 gboolean retval = FALSE;
452 if (!MODEST_IS_MAIL_OPERATION (self)) {
453 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
457 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
459 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
460 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
461 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
462 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
472 modest_mail_operation_get_id (ModestMailOperation *self)
474 ModestMailOperationPrivate *priv;
476 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
478 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
483 modest_mail_operation_set_id (ModestMailOperation *self,
486 ModestMailOperationPrivate *priv;
488 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
490 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
495 * Creates an image of the current state of a mail operation, the
496 * caller must free it
498 static ModestMailOperationState *
499 modest_mail_operation_clone_state (ModestMailOperation *self)
501 ModestMailOperationState *state;
502 ModestMailOperationPrivate *priv;
504 /* FIXME: this should be fixed properly
506 * in some cases, priv was NULL, so checking here to
509 g_return_val_if_fail (self, NULL);
510 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
511 g_return_val_if_fail (priv, NULL);
516 state = g_slice_new (ModestMailOperationState);
518 state->status = priv->status;
519 state->op_type = priv->op_type;
520 state->done = priv->done;
521 state->total = priv->total;
522 state->finished = modest_mail_operation_is_finished (self);
523 state->bytes_done = 0;
524 state->bytes_total = 0;
529 /* ******************************************************************* */
530 /* ************************** SEND ACTIONS ************************* */
531 /* ******************************************************************* */
534 modest_mail_operation_send_mail (ModestMailOperation *self,
535 TnyTransportAccount *transport_account,
538 TnySendQueue *send_queue = NULL;
539 ModestMailOperationPrivate *priv;
541 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
542 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
543 g_return_if_fail (TNY_IS_MSG (msg));
545 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
547 /* Get account and set it into mail_operation */
548 priv->account = g_object_ref (transport_account);
552 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
553 if (!TNY_IS_SEND_QUEUE(send_queue)) {
554 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
555 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
556 "modest: could not find send queue for account\n");
558 /* TODO: connect to the msg-sent in order to know when
559 the mail operation is finished */
560 tny_send_queue_add (send_queue, msg, &(priv->error));
561 /* TODO: we're setting always success, do the check in
563 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
566 /* TODO: do this in the handler of the "msg-sent"
567 signal.Notify about operation end */
568 modest_mail_operation_notify_end (self);
572 idle_create_msg_cb (gpointer idle_data)
574 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
576 gdk_threads_enter ();
577 info->callback (info->mail_op, info->msg, info->userdata);
578 gdk_threads_leave ();
579 g_object_unref (info->mail_op);
581 g_object_unref (info->msg);
582 g_slice_free (CreateMsgIdleInfo, info);
588 create_msg_thread (gpointer thread_data)
590 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
591 TnyMsg *new_msg = NULL;
592 ModestMailOperationPrivate *priv;
594 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
595 if (info->html_body == NULL) {
596 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
597 info->bcc, info->subject, info->plain_body,
598 info->attachments_list); /* FIXME: attachments */
600 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
601 info->bcc, info->subject, info->html_body,
602 info->plain_body, info->attachments_list);
607 /* Set priority flags in message */
608 header = tny_msg_get_header (new_msg);
609 if (info->priority_flags != 0)
610 tny_header_set_flags (header, info->priority_flags);
611 if (info->attachments_list != NULL) {
612 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
614 g_object_unref (G_OBJECT(header));
616 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
617 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
618 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
619 "modest: failed to create a new msg\n");
627 g_free (info->plain_body);
628 g_free (info->html_body);
629 g_free (info->subject);
630 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
631 g_list_free (info->attachments_list);
633 if (info->callback) {
634 CreateMsgIdleInfo *idle_info;
635 idle_info = g_slice_new0 (CreateMsgIdleInfo);
636 idle_info->mail_op = info->mail_op;
637 g_object_ref (info->mail_op);
638 idle_info->msg = new_msg;
640 g_object_ref (new_msg);
641 idle_info->callback = info->callback;
642 idle_info->userdata = info->userdata;
643 g_idle_add (idle_create_msg_cb, idle_info);
645 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
648 g_object_unref (info->mail_op);
649 g_slice_free (CreateMsgInfo, info);
654 modest_mail_operation_create_msg (ModestMailOperation *self,
655 const gchar *from, const gchar *to,
656 const gchar *cc, const gchar *bcc,
657 const gchar *subject, const gchar *plain_body,
658 const gchar *html_body,
659 const GList *attachments_list,
660 TnyHeaderFlags priority_flags,
661 ModestMailOperationCreateMsgCallback callback,
664 CreateMsgInfo *info = NULL;
666 info = g_slice_new0 (CreateMsgInfo);
667 info->mail_op = self;
670 info->from = g_strdup (from);
671 info->to = g_strdup (to);
672 info->cc = g_strdup (cc);
673 info->subject = g_strdup (subject);
674 info->plain_body = g_strdup (plain_body);
675 info->html_body = g_strdup (html_body);
676 info->attachments_list = g_list_copy ((GList *) attachments_list);
677 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
678 info->priority_flags = priority_flags;
680 info->callback = callback;
681 info->userdata = userdata;
683 g_thread_create (create_msg_thread, info, FALSE, NULL);
688 TnyTransportAccount *transport_account;
693 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
697 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
705 /* Call mail operation */
706 modest_mail_operation_send_mail (self, info->transport_account, msg);
708 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
710 if (info->draft_msg != NULL) {
711 header = tny_msg_get_header (info->draft_msg);
712 /* Note: This can fail (with a warning) if the message is not really already in a folder,
713 * because this function requires it to have a UID. */
714 tny_folder_remove_msg (folder, header, NULL);
715 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
716 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
717 g_object_unref (header);
723 g_object_unref (info->draft_msg);
724 if (info->transport_account)
725 g_object_unref (info->transport_account);
726 g_slice_free (SendNewMailInfo, info);
727 modest_mail_operation_notify_end (self);
731 modest_mail_operation_send_new_mail (ModestMailOperation *self,
732 TnyTransportAccount *transport_account,
734 const gchar *from, const gchar *to,
735 const gchar *cc, const gchar *bcc,
736 const gchar *subject, const gchar *plain_body,
737 const gchar *html_body,
738 const GList *attachments_list,
739 TnyHeaderFlags priority_flags)
741 ModestMailOperationPrivate *priv = NULL;
742 SendNewMailInfo *info;
744 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
745 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
747 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
749 /* Check parametters */
751 /* Set status failed and set an error */
752 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
753 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
754 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
755 _("Error trying to send a mail. You need to set at least one recipient"));
758 info = g_slice_new0 (SendNewMailInfo);
759 info->transport_account = transport_account;
760 if (transport_account)
761 g_object_ref (transport_account);
762 info->draft_msg = draft_msg;
764 g_object_ref (draft_msg);
765 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
766 attachments_list, priority_flags,
767 modest_mail_operation_send_new_mail_cb, info);
773 TnyTransportAccount *transport_account;
775 ModestMsgEditWindow *edit_window;
779 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
783 TnyFolder *folder = NULL;
784 TnyHeader *header = NULL;
785 ModestMailOperationPrivate *priv = NULL;
786 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
788 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
790 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
791 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
792 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
793 "modest: failed to create a new msg\n");
797 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
799 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
800 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
801 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
802 "modest: failed to create a new msg\n");
806 if (info->draft_msg != NULL) {
807 header = tny_msg_get_header (info->draft_msg);
808 /* Remove the old draft expunging it */
809 tny_folder_remove_msg (folder, header, NULL);
810 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
811 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
812 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
813 g_object_unref (header);
817 tny_folder_add_msg (folder, msg, &(priv->error));
820 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
822 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
824 if (info->edit_window)
825 modest_msg_edit_window_set_draft (info->edit_window, msg);
830 g_object_unref (G_OBJECT(folder));
831 if (info->edit_window)
832 g_object_unref (G_OBJECT(info->edit_window));
834 g_object_unref (G_OBJECT (info->draft_msg));
835 if (info->transport_account)
836 g_object_unref (G_OBJECT(info->transport_account));
837 g_slice_free (SaveToDraftsInfo, info);
839 modest_mail_operation_notify_end (self);
843 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
844 TnyTransportAccount *transport_account,
846 ModestMsgEditWindow *edit_window,
847 const gchar *from, const gchar *to,
848 const gchar *cc, const gchar *bcc,
849 const gchar *subject, const gchar *plain_body,
850 const gchar *html_body,
851 const GList *attachments_list,
852 TnyHeaderFlags priority_flags)
854 ModestMailOperationPrivate *priv = NULL;
855 SaveToDraftsInfo *info = NULL;
857 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
858 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
860 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
862 /* Get account and set it into mail_operation */
863 priv->account = g_object_ref (transport_account);
865 info = g_slice_new0 (SaveToDraftsInfo);
866 info->transport_account = g_object_ref (transport_account);
867 info->draft_msg = draft_msg;
869 g_object_ref (draft_msg);
870 info->edit_window = edit_window;
872 g_object_ref (edit_window);
874 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
875 attachments_list, priority_flags,
876 modest_mail_operation_save_to_drafts_cb, info);
882 ModestMailOperation *mail_op;
883 TnyStoreAccount *account;
884 TnyTransportAccount *transport_account;
887 gchar *retrieve_type;
889 UpdateAccountCallback callback;
896 ModestMailOperation *mail_op;
897 TnyMimePart *mime_part;
899 GetMimePartSizeCallback callback;
901 } GetMimePartSizeInfo;
903 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
904 /* We use this folder observer to track the headers that have been
905 * added to a folder */
908 TnyList *new_headers;
909 } InternalFolderObserver;
913 } InternalFolderObserverClass;
915 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
917 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
918 internal_folder_observer,
920 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
924 foreach_add_item (gpointer header, gpointer user_data)
926 tny_list_prepend (TNY_LIST (user_data),
927 g_object_ref (G_OBJECT (header)));
930 /* This is the method that looks for new messages in a folder */
932 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
934 InternalFolderObserver *derived = (InternalFolderObserver *)self;
936 TnyFolderChangeChanged changed;
938 changed = tny_folder_change_get_changed (change);
940 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
943 /* Get added headers */
944 list = tny_simple_list_new ();
945 tny_folder_change_get_added_headers (change, list);
947 /* Add them to the folder observer */
948 tny_list_foreach (list, foreach_add_item,
949 derived->new_headers);
951 g_object_unref (G_OBJECT (list));
956 internal_folder_observer_init (InternalFolderObserver *self)
958 self->new_headers = tny_simple_list_new ();
961 internal_folder_observer_finalize (GObject *object)
963 InternalFolderObserver *self;
965 self = (InternalFolderObserver *) object;
966 g_object_unref (self->new_headers);
968 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
971 tny_folder_observer_init (TnyFolderObserverIface *iface)
973 iface->update_func = internal_folder_observer_update;
976 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
978 GObjectClass *object_class;
980 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
981 object_class = (GObjectClass*) klass;
982 object_class->finalize = internal_folder_observer_finalize;
988 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
991 TnyList *folders = tny_simple_list_new ();
993 tny_folder_store_get_folders (store, folders, query, NULL);
994 iter = tny_list_create_iterator (folders);
996 while (!tny_iterator_is_done (iter)) {
998 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1000 tny_list_prepend (all_folders, G_OBJECT (folder));
1001 recurse_folders (folder, query, all_folders);
1002 g_object_unref (G_OBJECT (folder));
1004 tny_iterator_next (iter);
1006 g_object_unref (G_OBJECT (iter));
1007 g_object_unref (G_OBJECT (folders));
1011 * Issues the "progress-changed" signal. The timer won't be removed,
1012 * so you must call g_source_remove to stop the signal emission
1015 idle_notify_progress (gpointer data)
1017 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1018 ModestMailOperationState *state;
1020 state = modest_mail_operation_clone_state (mail_op);
1021 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1022 g_slice_free (ModestMailOperationState, state);
1028 * Issues the "progress-changed" signal and removes the timer. It uses
1029 * a lock to ensure that the progress information of the mail
1030 * operation is not modified while there are notifications pending
1033 idle_notify_progress_once (gpointer data)
1037 pair = (ModestPair *) data;
1039 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1041 /* Free the state and the reference to the mail operation */
1042 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1043 g_object_unref (pair->first);
1049 * Used to notify the queue from the main
1050 * loop. We call it inside an idle call to achieve that
1053 idle_notify_queue (gpointer data)
1055 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1057 /* Do not need to block, the notify end will do it for us */
1058 modest_mail_operation_notify_end (mail_op);
1059 g_object_unref (mail_op);
1065 compare_headers_by_date (gconstpointer a,
1068 TnyHeader **header1, **header2;
1069 time_t sent1, sent2;
1071 header1 = (TnyHeader **) a;
1072 header2 = (TnyHeader **) b;
1074 sent1 = tny_header_get_date_sent (*header1);
1075 sent2 = tny_header_get_date_sent (*header2);
1077 /* We want the most recent ones (greater time_t) at the
1086 set_last_updated_idle (gpointer data)
1088 gdk_threads_enter ();
1090 /* It does not matter if the time is not exactly the same than
1091 the time when this idle was called, it's just an
1092 approximation and it won't be very different */
1093 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1095 MODEST_ACCOUNT_LAST_UPDATED,
1099 gdk_threads_leave ();
1105 idle_update_account_cb (gpointer data)
1107 UpdateAccountInfo *idle_info;
1109 idle_info = (UpdateAccountInfo *) data;
1111 gdk_threads_enter ();
1112 idle_info->callback (idle_info->mail_op,
1113 idle_info->new_headers,
1114 idle_info->user_data);
1115 gdk_threads_leave ();
1118 g_object_unref (idle_info->mail_op);
1126 update_account_thread (gpointer thr_user_data)
1128 static gboolean first_time = TRUE;
1129 UpdateAccountInfo *info;
1130 TnyList *all_folders = NULL;
1131 GPtrArray *new_headers = NULL;
1132 TnyIterator *iter = NULL;
1133 TnyFolderStoreQuery *query = NULL;
1134 ModestMailOperationPrivate *priv = NULL;
1135 ModestTnySendQueue *send_queue = NULL;
1137 info = (UpdateAccountInfo *) thr_user_data;
1138 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1140 /* Get account and set it into mail_operation */
1141 priv->account = g_object_ref (info->account);
1144 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
1145 * show any updates unless we do that
1147 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
1148 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1150 /* Get all the folders. We can do it synchronously because
1151 we're already running in a different thread than the UI */
1152 all_folders = tny_simple_list_new ();
1153 query = tny_folder_store_query_new ();
1154 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1155 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1160 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1164 iter = tny_list_create_iterator (all_folders);
1165 while (!tny_iterator_is_done (iter)) {
1166 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1168 recurse_folders (folder, query, all_folders);
1169 tny_iterator_next (iter);
1171 g_object_unref (G_OBJECT (iter));
1173 /* Update status and notify. We need to call the notification
1174 with a source function in order to call it from the main
1175 loop. We need that in order not to get into trouble with
1176 Gtk+. We use a timeout in order to provide more status
1177 information, because the sync tinymail call does not
1178 provide it for the moment */
1179 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1181 /* Refresh folders */
1182 new_headers = g_ptr_array_new ();
1183 iter = tny_list_create_iterator (all_folders);
1185 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
1187 InternalFolderObserver *observer;
1188 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1190 /* Refresh the folder */
1191 /* Our observer receives notification of new emails during folder refreshes,
1192 * so we can use observer->new_headers.
1194 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1195 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1197 /* This gets the status information (headers) from the server.
1198 * We use the blocking version, because we are already in a separate
1202 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1203 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1206 /* If the retrieve type is full messages, refresh and get the messages */
1207 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1209 iter = tny_list_create_iterator (observer->new_headers);
1210 while (!tny_iterator_is_done (iter)) {
1211 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1213 /* Apply per-message size limits */
1214 if (tny_header_get_message_size (header) < info->max_size)
1215 g_ptr_array_add (new_headers, g_object_ref (header));
1217 g_object_unref (header);
1218 tny_iterator_next (iter);
1220 g_object_unref (iter);
1222 /* We do not need to do it the first time
1223 because it's automatically done by the tree
1225 if (G_UNLIKELY (!first_time))
1226 tny_folder_poke_status (TNY_FOLDER (folder));
1228 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1229 g_object_unref (observer);
1232 g_object_unref (G_OBJECT (folder));
1235 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1239 tny_iterator_next (iter);
1242 did_a_cancel = FALSE;
1244 g_object_unref (G_OBJECT (iter));
1245 g_source_remove (timeout);
1247 if (new_headers->len > 0) {
1251 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1253 /* Apply message count limit */
1254 /* If the number of messages exceeds the maximum, ask the
1255 * user to download them all,
1256 * as per the UI spec "Retrieval Limits" section in 4.4:
1258 if (new_headers->len > info->retrieve_limit) {
1259 /* TODO: Ask the user, instead of just
1261 * mail_nc_msg_count_limit_exceeded, with 'Get
1262 * all' and 'Newest only' buttons. */
1263 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1264 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1265 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1266 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1267 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1272 priv->total = MIN (new_headers->len, info->retrieve_limit);
1273 while (msg_num < priv->total) {
1275 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1276 TnyFolder *folder = tny_header_get_folder (header);
1277 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1278 ModestMailOperationState *state;
1282 /* We can not just use the mail operation because the
1283 values of done and total could change before the
1285 state = modest_mail_operation_clone_state (info->mail_op);
1286 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1287 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1288 pair, (GDestroyNotify) modest_pair_free);
1290 g_object_unref (msg);
1291 g_object_unref (folder);
1295 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1296 g_ptr_array_free (new_headers, FALSE);
1299 /* Perform send (if operation was not cancelled) */
1300 if (did_a_cancel) goto out;
1301 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1304 if (priv->account != NULL)
1305 g_object_unref (priv->account);
1306 priv->account = g_object_ref (info->transport_account);
1308 send_queue = modest_runtime_get_send_queue (info->transport_account);
1310 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1311 modest_tny_send_queue_try_to_send (send_queue);
1312 /* g_source_remove (timeout); */
1314 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1315 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1316 "cannot create a send queue for %s\n",
1317 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1318 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1321 /* Check if the operation was a success */
1323 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1325 /* Update the last updated key */
1326 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1327 set_last_updated_idle,
1328 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1329 (GDestroyNotify) g_free);
1334 if (info->callback) {
1335 UpdateAccountInfo *idle_info;
1337 /* This thread is not in the main lock */
1338 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1339 idle_info->mail_op = g_object_ref (info->mail_op);
1340 idle_info->new_headers = (new_headers) ? new_headers->len : 0;
1341 idle_info->callback = info->callback;
1342 g_idle_add (idle_update_account_cb, idle_info);
1345 /* Notify about operation end. Note that the info could be
1346 freed before this idle happens, but the mail operation will
1348 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1351 g_object_unref (query);
1352 g_object_unref (all_folders);
1353 g_object_unref (info->account);
1354 g_object_unref (info->transport_account);
1355 g_free (info->retrieve_type);
1356 g_slice_free (UpdateAccountInfo, info);
1364 modest_mail_operation_update_account (ModestMailOperation *self,
1365 const gchar *account_name,
1366 UpdateAccountCallback callback,
1369 GThread *thread = NULL;
1370 UpdateAccountInfo *info = NULL;
1371 ModestMailOperationPrivate *priv = NULL;
1372 ModestAccountMgr *mgr = NULL;
1373 TnyStoreAccount *store_account = NULL;
1374 TnyTransportAccount *transport_account = NULL;
1376 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1377 g_return_val_if_fail (account_name, FALSE);
1379 /* Init mail operation. Set total and done to 0, and do not
1380 update them, this way the progress objects will know that
1381 we have no clue about the number of the objects */
1382 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1385 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1387 /* Get the Modest account */
1388 store_account = (TnyStoreAccount *)
1389 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1391 TNY_ACCOUNT_TYPE_STORE);
1393 /* Make sure that we have a connection, and request one
1395 * TODO: Is there some way to trigger this for every attempt to
1396 * use the network? */
1397 if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
1400 if (!store_account) {
1401 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1402 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1403 "cannot get tny store account for %s\n", account_name);
1408 /* Get the transport account, we can not do it in the thread
1409 due to some problems with dbus */
1410 transport_account = (TnyTransportAccount *)
1411 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1413 if (!transport_account) {
1414 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1415 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1416 "cannot get tny transport account for %s\n", account_name);
1420 /* Create the helper object */
1421 info = g_slice_new (UpdateAccountInfo);
1422 info->mail_op = self;
1423 info->account = store_account;
1424 info->transport_account = transport_account;
1425 info->callback = callback;
1426 info->user_data = user_data;
1428 /* Get the message size limit */
1429 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1430 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1431 if (info->max_size == 0)
1432 info->max_size = G_MAXINT;
1434 info->max_size = info->max_size * KB;
1436 /* Get per-account retrieval type */
1437 mgr = modest_runtime_get_account_mgr ();
1438 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1439 MODEST_ACCOUNT_RETRIEVE, FALSE);
1441 /* Get per-account message amount retrieval limit */
1442 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1443 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1444 if (info->retrieve_limit == 0)
1445 info->retrieve_limit = G_MAXINT;
1447 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1449 /* Set account busy */
1450 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1451 priv->account_name = g_strdup(account_name);
1453 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1458 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1460 callback (self, 0, user_data);
1461 modest_mail_operation_notify_end (self);
1465 /* ******************************************************************* */
1466 /* ************************** STORE ACTIONS ************************* */
1467 /* ******************************************************************* */
1471 modest_mail_operation_create_folder (ModestMailOperation *self,
1472 TnyFolderStore *parent,
1475 ModestMailOperationPrivate *priv;
1476 TnyFolder *new_folder = NULL;
1478 TnyList *list = tny_simple_list_new ();
1479 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1481 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1482 g_return_val_if_fail (name, NULL);
1484 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1486 /* Check for already existing folder */
1487 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1488 tny_folder_store_get_folders (parent, list, query, NULL);
1489 g_object_unref (G_OBJECT (query));
1491 if (tny_list_get_length (list) > 0) {
1492 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1493 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1494 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1495 _CS("ckdg_ib_folder_already_exists"));
1498 g_object_unref (G_OBJECT (list));
1501 if (TNY_IS_FOLDER (parent)) {
1502 /* Check folder rules */
1503 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1504 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1505 /* Set status failed and set an error */
1506 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1507 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1508 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1509 _("mail_in_ui_folder_create_error"));
1513 if (!strcmp (name, " ") || strchr (name, '/')) {
1514 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1515 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1516 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1517 _("mail_in_ui_folder_create_error"));
1521 /* Create the folder */
1522 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1523 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1525 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1528 /* Notify about operation end */
1529 modest_mail_operation_notify_end (self);
1535 modest_mail_operation_remove_folder (ModestMailOperation *self,
1537 gboolean remove_to_trash)
1539 TnyAccount *account;
1540 ModestMailOperationPrivate *priv;
1541 ModestTnyFolderRules rules;
1543 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1544 g_return_if_fail (TNY_IS_FOLDER (folder));
1546 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1548 /* Check folder rules */
1549 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1550 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1551 /* Set status failed and set an error */
1552 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1553 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1554 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1555 _("mail_in_ui_folder_delete_error"));
1559 /* Get the account */
1560 account = modest_tny_folder_get_account (folder);
1561 priv->account = g_object_ref(account);
1563 /* Delete folder or move to trash */
1564 if (remove_to_trash) {
1565 TnyFolder *trash_folder = NULL;
1566 trash_folder = modest_tny_account_get_special_folder (account,
1567 TNY_FOLDER_TYPE_TRASH);
1568 /* TODO: error_handling */
1569 modest_mail_operation_xfer_folder (self, folder,
1570 TNY_FOLDER_STORE (trash_folder),
1573 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1575 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1576 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1579 g_object_unref (G_OBJECT (parent));
1581 g_object_unref (G_OBJECT (account));
1584 /* Notify about operation end */
1585 modest_mail_operation_notify_end (self);
1589 transfer_folder_status_cb (GObject *obj,
1593 ModestMailOperation *self;
1594 ModestMailOperationPrivate *priv;
1595 ModestMailOperationState *state;
1596 XFerMsgAsyncHelper *helper;
1598 g_return_if_fail (status != NULL);
1599 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1601 helper = (XFerMsgAsyncHelper *) user_data;
1602 g_return_if_fail (helper != NULL);
1604 self = helper->mail_op;
1605 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1607 priv->done = status->position;
1608 priv->total = status->of_total;
1610 state = modest_mail_operation_clone_state (self);
1611 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1612 g_slice_free (ModestMailOperationState, state);
1617 transfer_folder_cb (TnyFolder *folder,
1618 TnyFolderStore *into,
1620 TnyFolder *new_folder,
1624 XFerMsgAsyncHelper *helper;
1625 ModestMailOperation *self = NULL;
1626 ModestMailOperationPrivate *priv = NULL;
1628 helper = (XFerMsgAsyncHelper *) user_data;
1629 g_return_if_fail (helper != NULL);
1631 self = helper->mail_op;
1632 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1635 priv->error = g_error_copy (*err);
1637 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1638 } else if (cancelled) {
1639 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1640 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1641 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1642 _("Transference of %s was cancelled."),
1643 tny_folder_get_name (folder));
1646 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1649 /* Notify about operation end */
1650 modest_mail_operation_notify_end (self);
1652 /* If user defined callback function was defined, call it */
1653 if (helper->user_callback) {
1654 gdk_threads_enter ();
1655 helper->user_callback (priv->source, helper->user_data);
1656 gdk_threads_leave ();
1660 g_object_unref (helper->mail_op);
1661 g_slice_free (XFerMsgAsyncHelper, helper);
1666 * This function checks if the new name is a valid name for our local
1667 * folders account. The new name could not be the same than then name
1668 * of any of the mandatory local folders
1670 * We can not rely on tinymail because tinymail does not check the
1671 * name of the virtual folders that the account could have in the case
1672 * that we're doing a rename (because it directly calls Camel which
1673 * knows nothing about our virtual folders).
1675 * In the case of an actual copy/move (i.e. move/copy a folder between
1676 * accounts) tinymail uses the tny_folder_store_create_account which
1677 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1678 * checks the new name of the folder, so this call in that case
1679 * wouldn't be needed. *But* NOTE that if tinymail changes its
1680 * implementation (if folder transfers within the same account is no
1681 * longer implemented as a rename) this call will allow Modest to work
1684 * If the new name is not valid, this function will set the status to
1685 * failed and will set also an error in the mail operation
1688 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1689 TnyFolderStore *into,
1690 const gchar *new_name)
1692 if (TNY_IS_ACCOUNT (into) &&
1693 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1694 modest_tny_local_folders_account_extra_folder_exists (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1696 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1697 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1698 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1699 _("FIXME: folder name already in use"));
1706 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1708 TnyFolderStore *parent,
1709 gboolean delete_original,
1710 XferMsgsAsynUserCallback user_callback,
1713 ModestMailOperationPrivate *priv = NULL;
1714 ModestTnyFolderRules parent_rules = 0, rules;
1715 XFerMsgAsyncHelper *helper = NULL;
1717 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1718 g_return_if_fail (TNY_IS_FOLDER (folder));
1720 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1722 /* Get account and set it into mail_operation */
1723 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1724 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1726 /* Get folder rules */
1727 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1728 if (TNY_IS_FOLDER (parent))
1729 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1731 /* The moveable restriction is applied also to copy operation */
1732 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1733 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1734 /* Set status failed and set an error */
1735 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1736 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1737 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1738 _("mail_in_ui_folder_move_target_error"));
1740 /* Notify the queue */
1741 modest_mail_operation_notify_end (self);
1742 } else if (TNY_IS_FOLDER (parent) &&
1743 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1744 /* Set status failed and set an error */
1745 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1746 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1747 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1748 _("FIXME: parent folder does not accept new folders"));
1750 /* Notify the queue */
1751 modest_mail_operation_notify_end (self);
1755 /* Check that the new folder name is not used by any
1756 special local folder */
1757 if (new_name_valid_if_local_account (priv, parent,
1758 tny_folder_get_name (folder))) {
1759 /* Create the helper */
1760 helper = g_slice_new0 (XFerMsgAsyncHelper);
1761 helper->mail_op = g_object_ref(self);
1762 helper->dest_folder = NULL;
1763 helper->headers = NULL;
1764 helper->user_callback = user_callback;
1765 helper->user_data = user_data;
1767 /* Move/Copy folder */
1768 tny_folder_copy_async (folder,
1770 tny_folder_get_name (folder),
1773 transfer_folder_status_cb,
1776 modest_mail_operation_notify_end (self);
1782 modest_mail_operation_rename_folder (ModestMailOperation *self,
1786 ModestMailOperationPrivate *priv;
1787 ModestTnyFolderRules rules;
1788 XFerMsgAsyncHelper *helper;
1790 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1791 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1792 g_return_if_fail (name);
1794 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1796 /* Get account and set it into mail_operation */
1797 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1799 /* Check folder rules */
1800 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1801 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1802 /* Set status failed and set an error */
1803 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1804 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1805 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1806 _("FIXME: unable to rename"));
1808 /* Notify about operation end */
1809 modest_mail_operation_notify_end (self);
1810 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1811 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1812 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1813 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1814 _("FIXME: unable to rename"));
1815 /* Notify about operation end */
1816 modest_mail_operation_notify_end (self);
1818 TnyFolderStore *into;
1820 into = tny_folder_get_folder_store (folder);
1822 /* Check that the new folder name is not used by any
1823 special local folder */
1824 if (new_name_valid_if_local_account (priv, into, name)) {
1825 /* Create the helper */
1826 helper = g_slice_new0 (XFerMsgAsyncHelper);
1827 helper->mail_op = g_object_ref(self);
1828 helper->dest_folder = NULL;
1829 helper->headers = NULL;
1830 helper->user_callback = NULL;
1831 helper->user_data = NULL;
1833 /* Rename. Camel handles folder subscription/unsubscription */
1834 tny_folder_copy_async (folder, into, name, TRUE,
1836 transfer_folder_status_cb,
1839 modest_mail_operation_notify_end (self);
1841 g_object_unref (into);
1845 /* ******************************************************************* */
1846 /* ************************** MSG ACTIONS ************************* */
1847 /* ******************************************************************* */
1849 void modest_mail_operation_get_msg (ModestMailOperation *self,
1851 GetMsgAsyncUserCallback user_callback,
1854 GetMsgAsyncHelper *helper = NULL;
1856 ModestMailOperationPrivate *priv;
1858 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1859 g_return_if_fail (TNY_IS_HEADER (header));
1861 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1862 folder = tny_header_get_folder (header);
1864 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1866 /* Get message from folder */
1868 /* Get account and set it into mail_operation */
1869 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1871 helper = g_slice_new0 (GetMsgAsyncHelper);
1872 helper->mail_op = self;
1873 helper->user_callback = user_callback;
1874 helper->user_data = user_data;
1875 helper->header = g_object_ref (header);
1877 // The callback's reference so that the mail op is not
1878 // finalized until the async operation is completed even if
1879 // the user canceled the request meanwhile.
1880 g_object_ref (G_OBJECT (helper->mail_op));
1882 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1884 g_object_unref (G_OBJECT (folder));
1886 /* Set status failed and set an error */
1887 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1888 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1889 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1890 _("Error trying to get a message. No folder found for header"));
1892 /* Notify the queue */
1893 modest_mail_operation_notify_end (self);
1898 idle_get_mime_part_size_cb (gpointer userdata)
1900 GetMimePartSizeInfo *idle_info;
1902 idle_info = (GetMimePartSizeInfo *) userdata;
1904 gdk_threads_enter ();
1905 idle_info->callback (idle_info->mail_op,
1907 idle_info->userdata);
1908 gdk_threads_leave ();
1910 g_object_unref (idle_info->mail_op);
1911 g_slice_free (GetMimePartSizeInfo, idle_info);
1917 get_mime_part_size_thread (gpointer thr_user_data)
1919 GetMimePartSizeInfo *info;
1920 gchar read_buffer[GET_SIZE_BUFFER_SIZE];
1924 ModestMailOperationPrivate *priv;
1926 info = (GetMimePartSizeInfo *) thr_user_data;
1927 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1929 stream = tny_camel_mem_stream_new ();
1930 tny_mime_part_decode_to_stream (info->mime_part, stream);
1931 tny_stream_reset (stream);
1932 if (tny_stream_is_eos (stream)) {
1933 tny_stream_close (stream);
1934 stream = tny_mime_part_get_stream (info->mime_part);
1937 while (!tny_stream_is_eos (stream)) {
1938 readed_size = tny_stream_read (stream, read_buffer, GET_SIZE_BUFFER_SIZE);
1939 total += readed_size;
1942 if (info->callback) {
1943 GetMimePartSizeInfo *idle_info;
1945 idle_info = g_slice_new0 (GetMimePartSizeInfo);
1946 idle_info->mail_op = g_object_ref (info->mail_op);
1947 idle_info->size = total;
1948 idle_info->callback = info->callback;
1949 idle_info->userdata = info->userdata;
1950 g_idle_add (idle_get_mime_part_size_cb, idle_info);
1953 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1955 g_object_unref (info->mail_op);
1956 g_object_unref (stream);
1957 g_object_unref (info->mime_part);
1958 g_slice_free (GetMimePartSizeInfo, info);
1964 modest_mail_operation_get_mime_part_size (ModestMailOperation *self,
1966 GetMimePartSizeCallback user_callback,
1968 GDestroyNotify notify)
1970 GetMimePartSizeInfo *info;
1971 ModestMailOperationPrivate *priv;
1974 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1975 g_return_if_fail (TNY_IS_MIME_PART (part));
1977 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1979 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1980 info = g_slice_new0 (GetMimePartSizeInfo);
1981 info->mail_op = g_object_ref (self);
1982 info->mime_part = g_object_ref (part);
1983 info->callback = user_callback;
1984 info->userdata = user_data;
1986 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
1991 get_msg_cb (TnyFolder *folder,
1997 GetMsgAsyncHelper *helper = NULL;
1998 ModestMailOperation *self = NULL;
1999 ModestMailOperationPrivate *priv = NULL;
2001 helper = (GetMsgAsyncHelper *) user_data;
2002 g_return_if_fail (helper != NULL);
2003 self = helper->mail_op;
2004 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2005 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2007 /* Check errors and cancel */
2009 priv->error = g_error_copy (*error);
2010 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2011 } else if (cancelled) {
2012 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2013 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2014 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2015 _("Error trying to refresh the contents of %s"),
2016 tny_folder_get_name (folder));
2018 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2021 /* If user defined callback function was defined, call it even
2022 if the operation failed*/
2023 if (helper->user_callback) {
2024 /* This callback is called into an iddle by tinymail,
2025 and idles are not in the main lock */
2026 gdk_threads_enter ();
2027 helper->user_callback (self, helper->header, msg, helper->user_data);
2028 gdk_threads_leave ();
2031 /* Notify about operation end */
2032 modest_mail_operation_notify_end (self);
2034 g_object_unref (helper->mail_op);
2035 g_object_unref (helper->header);
2036 g_slice_free (GetMsgAsyncHelper, helper);
2041 get_msg_status_cb (GObject *obj,
2045 GetMsgAsyncHelper *helper = NULL;
2046 ModestMailOperation *self;
2047 ModestMailOperationPrivate *priv;
2048 ModestMailOperationState *state;
2050 g_return_if_fail (status != NULL);
2051 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2053 helper = (GetMsgAsyncHelper *) user_data;
2054 g_return_if_fail (helper != NULL);
2056 self = helper->mail_op;
2057 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2059 if(priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2060 TnyFolder *folder = tny_header_get_folder (helper->header);
2062 TnyAccount *account;
2063 account = tny_folder_get_account (folder);
2065 tny_account_cancel (account);
2066 g_object_unref (account);
2068 g_object_unref (folder);
2077 state = modest_mail_operation_clone_state (self);
2078 state->bytes_done = status->position;
2079 state->bytes_total = status->of_total;
2080 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2081 g_slice_free (ModestMailOperationState, state);
2084 /****************************************************/
2086 ModestMailOperation *mail_op;
2088 GetMsgAsyncUserCallback user_callback;
2090 GDestroyNotify notify;
2094 GetMsgAsyncUserCallback user_callback;
2098 ModestMailOperation *mail_op;
2099 } NotifyGetMsgsInfo;
2103 * Used by get_msgs_full_thread to call the user_callback for each
2104 * message that has been read
2107 notify_get_msgs_full (gpointer data)
2109 NotifyGetMsgsInfo *info;
2111 info = (NotifyGetMsgsInfo *) data;
2113 /* Call the user callback. Idles are not in the main lock, so
2115 gdk_threads_enter ();
2116 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2117 gdk_threads_leave ();
2119 g_slice_free (NotifyGetMsgsInfo, info);
2125 * Used by get_msgs_full_thread to free al the thread resources and to
2126 * call the destroy function for the passed user_data
2129 get_msgs_full_destroyer (gpointer data)
2131 GetFullMsgsInfo *info;
2133 info = (GetFullMsgsInfo *) data;
2136 gdk_threads_enter ();
2137 info->notify (info->user_data);
2138 gdk_threads_leave ();
2142 g_object_unref (info->headers);
2143 g_slice_free (GetFullMsgsInfo, info);
2149 get_msgs_full_thread (gpointer thr_user_data)
2151 GetFullMsgsInfo *info;
2152 ModestMailOperationPrivate *priv = NULL;
2153 TnyIterator *iter = NULL;
2155 info = (GetFullMsgsInfo *) thr_user_data;
2156 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2158 iter = tny_list_create_iterator (info->headers);
2159 while (!tny_iterator_is_done (iter)) {
2163 header = TNY_HEADER (tny_iterator_get_current (iter));
2164 folder = tny_header_get_folder (header);
2166 /* Get message from folder */
2169 /* The callback will call it per each header */
2170 msg = tny_folder_get_msg (folder, header, &(priv->error));
2173 ModestMailOperationState *state;
2178 /* notify progress */
2179 state = modest_mail_operation_clone_state (info->mail_op);
2180 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2181 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2182 pair, (GDestroyNotify) modest_pair_free);
2184 /* The callback is the responsible for
2185 freeing the message */
2186 if (info->user_callback) {
2187 NotifyGetMsgsInfo *info_notify;
2188 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2189 info_notify->user_callback = info->user_callback;
2190 info_notify->mail_op = info->mail_op;
2191 info_notify->header = g_object_ref (header);
2192 info_notify->msg = g_object_ref (msg);
2193 info_notify->user_data = info->user_data;
2194 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2195 notify_get_msgs_full,
2198 g_object_unref (msg);
2201 /* Set status failed and set an error */
2202 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2203 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2204 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2205 "Error trying to get a message. No folder found for header");
2207 g_object_unref (header);
2208 tny_iterator_next (iter);
2211 /* Set operation status */
2212 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2213 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2215 /* Notify about operation end */
2216 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2218 /* Free thread resources. Will be called after all previous idles */
2219 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2225 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2226 TnyList *header_list,
2227 GetMsgAsyncUserCallback user_callback,
2229 GDestroyNotify notify)
2231 TnyHeader *header = NULL;
2232 TnyFolder *folder = NULL;
2234 ModestMailOperationPrivate *priv = NULL;
2235 GetFullMsgsInfo *info = NULL;
2236 gboolean size_ok = TRUE;
2238 TnyIterator *iter = NULL;
2240 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2242 /* Init mail operation */
2243 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2244 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2246 priv->total = tny_list_get_length(header_list);
2248 /* Get account and set it into mail_operation */
2249 if (tny_list_get_length (header_list) >= 1) {
2250 iter = tny_list_create_iterator (header_list);
2251 header = TNY_HEADER (tny_iterator_get_current (iter));
2252 folder = tny_header_get_folder (header);
2253 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2254 g_object_unref (header);
2255 g_object_unref (folder);
2257 if (tny_list_get_length (header_list) == 1) {
2258 g_object_unref (iter);
2263 /* Get msg size limit */
2264 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2265 MODEST_CONF_MSG_SIZE_LIMIT,
2268 g_clear_error (&(priv->error));
2269 max_size = G_MAXINT;
2271 max_size = max_size * KB;
2274 /* Check message size limits. If there is only one message
2275 always retrieve it */
2277 while (!tny_iterator_is_done (iter) && size_ok) {
2278 header = TNY_HEADER (tny_iterator_get_current (iter));
2279 if (tny_header_get_message_size (header) >= max_size)
2281 g_object_unref (header);
2282 tny_iterator_next (iter);
2284 g_object_unref (iter);
2288 /* Create the info */
2289 info = g_slice_new0 (GetFullMsgsInfo);
2290 info->mail_op = self;
2291 info->user_callback = user_callback;
2292 info->user_data = user_data;
2293 info->headers = g_object_ref (header_list);
2294 info->notify = notify;
2296 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2298 /* Set status failed and set an error */
2299 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2300 /* FIXME: the error msg is different for pop */
2301 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2302 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2303 _("emev_ni_ui_imap_msg_size_exceed_error"));
2304 /* Remove from queue and free resources */
2305 modest_mail_operation_notify_end (self);
2313 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2314 gboolean remove_to_trash /*ignored*/)
2317 ModestMailOperationPrivate *priv;
2319 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2320 g_return_if_fail (TNY_IS_HEADER (header));
2322 if (remove_to_trash)
2323 g_warning ("remove to trash is not implemented");
2325 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2326 folder = tny_header_get_folder (header);
2328 /* Get account and set it into mail_operation */
2329 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2331 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2334 tny_folder_remove_msg (folder, header, &(priv->error));
2336 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2337 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2339 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2340 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2341 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2342 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2345 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2351 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2353 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2356 g_object_unref (G_OBJECT (folder));
2358 /* Notify about operation end */
2359 modest_mail_operation_notify_end (self);
2363 transfer_msgs_status_cb (GObject *obj,
2367 XFerMsgAsyncHelper *helper = NULL;
2368 ModestMailOperation *self;
2369 ModestMailOperationPrivate *priv;
2370 ModestMailOperationState *state;
2373 g_return_if_fail (status != NULL);
2374 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2376 helper = (XFerMsgAsyncHelper *) user_data;
2377 g_return_if_fail (helper != NULL);
2379 self = helper->mail_op;
2380 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2382 priv->done = status->position;
2383 priv->total = status->of_total;
2385 state = modest_mail_operation_clone_state (self);
2386 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2387 g_slice_free (ModestMailOperationState, state);
2392 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2394 XFerMsgAsyncHelper *helper;
2395 ModestMailOperation *self;
2396 ModestMailOperationPrivate *priv;
2398 helper = (XFerMsgAsyncHelper *) user_data;
2399 self = helper->mail_op;
2401 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2404 priv->error = g_error_copy (*err);
2406 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2407 } else if (cancelled) {
2408 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2409 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2410 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2411 _("Error trying to refresh the contents of %s"),
2412 tny_folder_get_name (folder));
2415 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2418 /* Notify about operation end */
2419 modest_mail_operation_notify_end (self);
2421 /* If user defined callback function was defined, call it */
2422 if (helper->user_callback) {
2423 gdk_threads_enter ();
2424 helper->user_callback (priv->source, helper->user_data);
2425 gdk_threads_leave ();
2429 g_object_unref (helper->headers);
2430 g_object_unref (helper->dest_folder);
2431 g_object_unref (helper->mail_op);
2432 g_slice_free (XFerMsgAsyncHelper, helper);
2433 g_object_unref (folder);
2438 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2441 gboolean delete_original,
2442 XferMsgsAsynUserCallback user_callback,
2445 ModestMailOperationPrivate *priv;
2447 TnyFolder *src_folder;
2448 XFerMsgAsyncHelper *helper;
2450 ModestTnyFolderRules rules;
2451 const gchar *id1 = NULL;
2452 const gchar *id2 = NULL;
2453 gboolean same_folder = FALSE;
2455 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2456 g_return_if_fail (TNY_IS_LIST (headers));
2457 g_return_if_fail (TNY_IS_FOLDER (folder));
2459 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2462 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2464 /* Apply folder rules */
2465 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2466 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2467 /* Set status failed and set an error */
2468 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2469 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2470 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2471 _CS("ckct_ib_unable_to_paste_here"));
2472 /* Notify the queue */
2473 modest_mail_operation_notify_end (self);
2477 /* Get source folder */
2478 iter = tny_list_create_iterator (headers);
2479 header = TNY_HEADER (tny_iterator_get_current (iter));
2480 src_folder = tny_header_get_folder (header);
2481 g_object_unref (header);
2482 g_object_unref (iter);
2484 /* Check folder source and destination */
2485 id1 = tny_folder_get_id (src_folder);
2486 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2487 same_folder = !g_ascii_strcasecmp (id1, id2);
2489 /* Set status failed and set an error */
2490 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2491 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2492 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2493 _("mcen_ib_unable_to_copy_samefolder"));
2495 /* Notify the queue */
2496 modest_mail_operation_notify_end (self);
2499 g_object_unref (src_folder);
2503 /* Create the helper */
2504 helper = g_slice_new0 (XFerMsgAsyncHelper);
2505 helper->mail_op = g_object_ref(self);
2506 helper->dest_folder = g_object_ref(folder);
2507 helper->headers = g_object_ref(headers);
2508 helper->user_callback = user_callback;
2509 helper->user_data = user_data;
2511 /* Get account and set it into mail_operation */
2512 priv->account = modest_tny_folder_get_account (src_folder);
2514 /* Transfer messages */
2515 tny_folder_transfer_msgs_async (src_folder,
2520 transfer_msgs_status_cb,
2526 on_refresh_folder (TnyFolder *folder,
2531 RefreshAsyncHelper *helper = NULL;
2532 ModestMailOperation *self = NULL;
2533 ModestMailOperationPrivate *priv = NULL;
2535 helper = (RefreshAsyncHelper *) user_data;
2536 self = helper->mail_op;
2537 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2540 priv->error = g_error_copy (*error);
2541 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2546 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2547 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2548 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2549 _("Error trying to refresh the contents of %s"),
2550 tny_folder_get_name (folder));
2554 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2556 /* Call user defined callback, if it exists */
2557 if (helper->user_callback) {
2558 gdk_threads_enter ();
2559 helper->user_callback (self, folder, helper->user_data);
2560 gdk_threads_leave ();
2564 g_object_unref (helper->mail_op);
2565 g_slice_free (RefreshAsyncHelper, helper);
2567 /* Notify about operation end */
2568 modest_mail_operation_notify_end (self);
2572 on_refresh_folder_status_update (GObject *obj,
2576 RefreshAsyncHelper *helper = NULL;
2577 ModestMailOperation *self = NULL;
2578 ModestMailOperationPrivate *priv = NULL;
2579 ModestMailOperationState *state;
2581 g_return_if_fail (user_data != NULL);
2582 g_return_if_fail (status != NULL);
2583 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2585 helper = (RefreshAsyncHelper *) user_data;
2586 self = helper->mail_op;
2587 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2589 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2591 priv->done = status->position;
2592 priv->total = status->of_total;
2594 state = modest_mail_operation_clone_state (self);
2595 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2596 g_slice_free (ModestMailOperationState, state);
2600 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2602 RefreshAsyncUserCallback user_callback,
2605 ModestMailOperationPrivate *priv = NULL;
2606 RefreshAsyncHelper *helper = NULL;
2608 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2610 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2612 /* Get account and set it into mail_operation */
2613 priv->account = modest_tny_folder_get_account (folder);
2615 /* Create the helper */
2616 helper = g_slice_new0 (RefreshAsyncHelper);
2617 helper->mail_op = g_object_ref(self);
2618 helper->user_callback = user_callback;
2619 helper->user_data = user_data;
2621 /* Refresh the folder. TODO: tinymail could issue a status
2622 updates before the callback call then this could happen. We
2623 must review the design */
2624 tny_folder_refresh_async (folder,
2626 on_refresh_folder_status_update,
2632 * It's used by the mail operation queue to notify the observers
2633 * attached to that signal that the operation finished. We need to use
2634 * that because tinymail does not give us the progress of a given
2635 * operation when it finishes (it directly calls the operation
2639 modest_mail_operation_notify_end (ModestMailOperation *self)
2641 ModestMailOperationState *state;
2642 ModestMailOperationPrivate *priv = NULL;
2644 g_return_if_fail (self);
2646 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2648 /* Set the account back to not busy */
2649 if (priv->account_name) {
2650 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2651 priv->account_name, FALSE);
2652 g_free(priv->account_name);
2653 priv->account_name = NULL;
2656 /* Notify the observers about the mail opertation end */
2657 state = modest_mail_operation_clone_state (self);
2658 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2659 g_slice_free (ModestMailOperationState, state);