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-platform-factory.h"
55 #include "modest-marshal.h"
56 #include "modest-error.h"
57 #include "modest-mail-operation.h"
58 #include "widgets/modest-header-view.h"
59 #include "widgets/modest-main-window.h"
62 #define GET_SIZE_BUFFER_SIZE 128
64 /* 'private'/'protected' functions */
65 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
66 static void modest_mail_operation_init (ModestMailOperation *obj);
67 static void modest_mail_operation_finalize (GObject *obj);
69 static void get_msg_cb (TnyFolder *folder,
75 static void get_msg_status_cb (GObject *obj,
79 static void modest_mail_operation_notify_end (ModestMailOperation *self);
81 static gboolean did_a_cancel = FALSE;
83 enum _ModestMailOperationSignals
85 PROGRESS_CHANGED_SIGNAL,
90 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
91 struct _ModestMailOperationPrivate {
98 ErrorCheckingUserCallback error_checking;
99 gpointer error_checking_user_data;
100 ModestMailOperationStatus status;
101 ModestMailOperationTypeOperation op_type;
104 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
105 MODEST_TYPE_MAIL_OPERATION, \
106 ModestMailOperationPrivate))
108 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
109 priv->status = new_status;\
112 typedef struct _GetMsgAsyncHelper {
113 ModestMailOperation *mail_op;
115 GetMsgAsyncUserCallback user_callback;
119 typedef struct _RefreshAsyncHelper {
120 ModestMailOperation *mail_op;
121 RefreshAsyncUserCallback user_callback;
123 } RefreshAsyncHelper;
125 typedef struct _XFerMsgAsyncHelper
127 ModestMailOperation *mail_op;
129 TnyFolder *dest_folder;
130 XferMsgsAsynUserCallback user_callback;
132 } XFerMsgAsyncHelper;
134 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
138 static void modest_mail_operation_create_msg (ModestMailOperation *self,
139 const gchar *from, const gchar *to,
140 const gchar *cc, const gchar *bcc,
141 const gchar *subject, const gchar *plain_body,
142 const gchar *html_body, const GList *attachments_list,
143 TnyHeaderFlags priority_flags,
144 ModestMailOperationCreateMsgCallback callback,
147 static gboolean idle_notify_queue (gpointer data);
150 ModestMailOperation *mail_op;
158 GList *attachments_list;
159 TnyHeaderFlags priority_flags;
160 ModestMailOperationCreateMsgCallback callback;
166 ModestMailOperation *mail_op;
168 ModestMailOperationCreateMsgCallback callback;
173 static GObjectClass *parent_class = NULL;
175 static guint signals[NUM_SIGNALS] = {0};
178 modest_mail_operation_get_type (void)
180 static GType my_type = 0;
182 static const GTypeInfo my_info = {
183 sizeof(ModestMailOperationClass),
184 NULL, /* base init */
185 NULL, /* base finalize */
186 (GClassInitFunc) modest_mail_operation_class_init,
187 NULL, /* class finalize */
188 NULL, /* class data */
189 sizeof(ModestMailOperation),
191 (GInstanceInitFunc) modest_mail_operation_init,
194 my_type = g_type_register_static (G_TYPE_OBJECT,
195 "ModestMailOperation",
202 modest_mail_operation_class_init (ModestMailOperationClass *klass)
204 GObjectClass *gobject_class;
205 gobject_class = (GObjectClass*) klass;
207 parent_class = g_type_class_peek_parent (klass);
208 gobject_class->finalize = modest_mail_operation_finalize;
210 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
213 * ModestMailOperation::progress-changed
214 * @self: the #MailOperation that emits the signal
215 * @user_data: user data set when the signal handler was connected
217 * Emitted when the progress of a mail operation changes
219 signals[PROGRESS_CHANGED_SIGNAL] =
220 g_signal_new ("progress-changed",
221 G_TYPE_FROM_CLASS (gobject_class),
223 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
225 g_cclosure_marshal_VOID__POINTER,
226 G_TYPE_NONE, 1, G_TYPE_POINTER);
231 modest_mail_operation_init (ModestMailOperation *obj)
233 ModestMailOperationPrivate *priv;
235 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
237 priv->account = NULL;
238 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
239 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
244 priv->error_checking = NULL;
245 priv->error_checking_user_data = NULL;
249 modest_mail_operation_finalize (GObject *obj)
251 ModestMailOperationPrivate *priv;
253 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
258 g_error_free (priv->error);
262 g_object_unref (priv->source);
266 g_object_unref (priv->account);
267 priv->account = NULL;
271 G_OBJECT_CLASS(parent_class)->finalize (obj);
275 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
278 ModestMailOperation *obj;
279 ModestMailOperationPrivate *priv;
281 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
282 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
284 priv->op_type = op_type;
286 priv->source = g_object_ref(source);
292 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
294 ErrorCheckingUserCallback error_handler,
297 ModestMailOperation *obj;
298 ModestMailOperationPrivate *priv;
300 obj = modest_mail_operation_new (op_type, source);
301 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
303 g_return_val_if_fail (error_handler != NULL, obj);
304 priv->error_checking = error_handler;
310 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
312 ModestMailOperationPrivate *priv;
314 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
315 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
317 if (priv->error_checking != NULL)
318 priv->error_checking (self, priv->error_checking_user_data);
322 ModestMailOperationTypeOperation
323 modest_mail_operation_get_type_operation (ModestMailOperation *self)
325 ModestMailOperationPrivate *priv;
327 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
329 return priv->op_type;
333 modest_mail_operation_is_mine (ModestMailOperation *self,
336 ModestMailOperationPrivate *priv;
338 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
339 if (priv->source == NULL) return FALSE;
341 return priv->source == me;
345 modest_mail_operation_get_source (ModestMailOperation *self)
347 ModestMailOperationPrivate *priv;
349 g_return_val_if_fail (self, NULL);
351 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
353 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
357 return g_object_ref (priv->source);
360 ModestMailOperationStatus
361 modest_mail_operation_get_status (ModestMailOperation *self)
363 ModestMailOperationPrivate *priv;
365 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
366 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
367 MODEST_MAIL_OPERATION_STATUS_INVALID);
369 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
371 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
372 return MODEST_MAIL_OPERATION_STATUS_INVALID;
379 modest_mail_operation_get_error (ModestMailOperation *self)
381 ModestMailOperationPrivate *priv;
383 g_return_val_if_fail (self, NULL);
384 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
386 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
389 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
397 modest_mail_operation_cancel (ModestMailOperation *self)
399 ModestMailOperationPrivate *priv;
401 if (!MODEST_IS_MAIL_OPERATION (self)) {
402 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
406 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
408 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
415 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
417 /* This emits progress-changed on which the mail operation queue is
418 * listening, so the mail operation is correctly removed from the
419 * queue without further explicit calls. */
420 modest_mail_operation_notify_end (self);
426 modest_mail_operation_get_task_done (ModestMailOperation *self)
428 ModestMailOperationPrivate *priv;
430 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
432 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
437 modest_mail_operation_get_task_total (ModestMailOperation *self)
439 ModestMailOperationPrivate *priv;
441 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
443 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
448 modest_mail_operation_is_finished (ModestMailOperation *self)
450 ModestMailOperationPrivate *priv;
451 gboolean retval = FALSE;
453 if (!MODEST_IS_MAIL_OPERATION (self)) {
454 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
458 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
460 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
461 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
462 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
463 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
473 modest_mail_operation_get_id (ModestMailOperation *self)
475 ModestMailOperationPrivate *priv;
477 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
479 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
484 modest_mail_operation_set_id (ModestMailOperation *self,
487 ModestMailOperationPrivate *priv;
489 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
491 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
496 * Creates an image of the current state of a mail operation, the
497 * caller must free it
499 static ModestMailOperationState *
500 modest_mail_operation_clone_state (ModestMailOperation *self)
502 ModestMailOperationState *state;
503 ModestMailOperationPrivate *priv;
505 /* FIXME: this should be fixed properly
507 * in some cases, priv was NULL, so checking here to
510 g_return_val_if_fail (self, NULL);
511 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
512 g_return_val_if_fail (priv, NULL);
517 state = g_slice_new (ModestMailOperationState);
519 state->status = priv->status;
520 state->op_type = priv->op_type;
521 state->done = priv->done;
522 state->total = priv->total;
523 state->finished = modest_mail_operation_is_finished (self);
524 state->bytes_done = 0;
525 state->bytes_total = 0;
530 /* ******************************************************************* */
531 /* ************************** SEND ACTIONS ************************* */
532 /* ******************************************************************* */
535 modest_mail_operation_send_mail (ModestMailOperation *self,
536 TnyTransportAccount *transport_account,
539 TnySendQueue *send_queue = NULL;
540 ModestMailOperationPrivate *priv;
542 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
543 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
544 g_return_if_fail (TNY_IS_MSG (msg));
546 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
548 /* Get account and set it into mail_operation */
549 priv->account = g_object_ref (transport_account);
553 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
554 if (!TNY_IS_SEND_QUEUE(send_queue)) {
555 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
556 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
557 "modest: could not find send queue for account\n");
559 /* TODO: connect to the msg-sent in order to know when
560 the mail operation is finished */
561 tny_send_queue_add (send_queue, msg, &(priv->error));
562 /* TODO: we're setting always success, do the check in
564 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
567 /* TODO: do this in the handler of the "msg-sent"
568 signal.Notify about operation end */
569 modest_mail_operation_notify_end (self);
573 idle_create_msg_cb (gpointer idle_data)
575 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
577 gdk_threads_enter ();
578 info->callback (info->mail_op, info->msg, info->userdata);
579 gdk_threads_leave ();
580 g_object_unref (info->mail_op);
582 g_object_unref (info->msg);
583 g_slice_free (CreateMsgIdleInfo, info);
589 create_msg_thread (gpointer thread_data)
591 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
592 TnyMsg *new_msg = NULL;
593 ModestMailOperationPrivate *priv;
595 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
596 if (info->html_body == NULL) {
597 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
598 info->bcc, info->subject, info->plain_body,
599 info->attachments_list); /* FIXME: attachments */
601 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
602 info->bcc, info->subject, info->html_body,
603 info->plain_body, info->attachments_list);
608 /* Set priority flags in message */
609 header = tny_msg_get_header (new_msg);
610 if (info->priority_flags != 0)
611 tny_header_set_flags (header, info->priority_flags);
612 if (info->attachments_list != NULL) {
613 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
615 g_object_unref (G_OBJECT(header));
617 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
618 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
619 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
620 "modest: failed to create a new msg\n");
628 g_free (info->plain_body);
629 g_free (info->html_body);
630 g_free (info->subject);
631 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
632 g_list_free (info->attachments_list);
634 if (info->callback) {
635 CreateMsgIdleInfo *idle_info;
636 idle_info = g_slice_new0 (CreateMsgIdleInfo);
637 idle_info->mail_op = info->mail_op;
638 g_object_ref (info->mail_op);
639 idle_info->msg = new_msg;
641 g_object_ref (new_msg);
642 idle_info->callback = info->callback;
643 idle_info->userdata = info->userdata;
644 g_idle_add (idle_create_msg_cb, idle_info);
646 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
649 g_object_unref (info->mail_op);
650 g_slice_free (CreateMsgInfo, info);
655 modest_mail_operation_create_msg (ModestMailOperation *self,
656 const gchar *from, const gchar *to,
657 const gchar *cc, const gchar *bcc,
658 const gchar *subject, const gchar *plain_body,
659 const gchar *html_body,
660 const GList *attachments_list,
661 TnyHeaderFlags priority_flags,
662 ModestMailOperationCreateMsgCallback callback,
665 CreateMsgInfo *info = NULL;
667 info = g_slice_new0 (CreateMsgInfo);
668 info->mail_op = self;
671 info->from = g_strdup (from);
672 info->to = g_strdup (to);
673 info->cc = g_strdup (cc);
674 info->subject = g_strdup (subject);
675 info->plain_body = g_strdup (plain_body);
676 info->html_body = g_strdup (html_body);
677 info->attachments_list = g_list_copy ((GList *) attachments_list);
678 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
679 info->priority_flags = priority_flags;
681 info->callback = callback;
682 info->userdata = userdata;
684 g_thread_create (create_msg_thread, info, FALSE, NULL);
689 TnyTransportAccount *transport_account;
694 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
698 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
706 /* Call mail operation */
707 modest_mail_operation_send_mail (self, info->transport_account, msg);
709 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
711 if (info->draft_msg != NULL) {
712 header = tny_msg_get_header (info->draft_msg);
713 /* Note: This can fail (with a warning) if the message is not really already in a folder,
714 * because this function requires it to have a UID. */
715 tny_folder_remove_msg (folder, header, NULL);
716 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
717 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
718 g_object_unref (header);
724 g_object_unref (info->draft_msg);
725 if (info->transport_account)
726 g_object_unref (info->transport_account);
727 g_slice_free (SendNewMailInfo, info);
728 modest_mail_operation_notify_end (self);
732 modest_mail_operation_send_new_mail (ModestMailOperation *self,
733 TnyTransportAccount *transport_account,
735 const gchar *from, const gchar *to,
736 const gchar *cc, const gchar *bcc,
737 const gchar *subject, const gchar *plain_body,
738 const gchar *html_body,
739 const GList *attachments_list,
740 TnyHeaderFlags priority_flags)
742 ModestMailOperationPrivate *priv = NULL;
743 SendNewMailInfo *info;
745 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
746 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
748 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
750 /* Check parametters */
752 /* Set status failed and set an error */
753 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
754 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
755 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
756 _("Error trying to send a mail. You need to set at least one recipient"));
759 info = g_slice_new0 (SendNewMailInfo);
760 info->transport_account = transport_account;
761 if (transport_account)
762 g_object_ref (transport_account);
763 info->draft_msg = draft_msg;
765 g_object_ref (draft_msg);
766 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
767 attachments_list, priority_flags,
768 modest_mail_operation_send_new_mail_cb, info);
774 TnyTransportAccount *transport_account;
776 ModestMsgEditWindow *edit_window;
780 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
784 TnyFolder *folder = NULL;
785 TnyHeader *header = NULL;
786 ModestMailOperationPrivate *priv = NULL;
787 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
789 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
791 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
792 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
793 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
794 "modest: failed to create a new msg\n");
798 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
800 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
801 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
802 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
803 "modest: failed to create a new msg\n");
807 if (info->draft_msg != NULL) {
808 header = tny_msg_get_header (info->draft_msg);
809 /* Remove the old draft expunging it */
810 tny_folder_remove_msg (folder, header, NULL);
811 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
812 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
813 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
814 g_object_unref (header);
818 tny_folder_add_msg (folder, msg, &(priv->error));
821 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
823 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
825 if (info->edit_window)
826 modest_msg_edit_window_set_draft (info->edit_window, msg);
831 g_object_unref (G_OBJECT(folder));
832 if (info->edit_window)
833 g_object_unref (G_OBJECT(info->edit_window));
835 g_object_unref (G_OBJECT (info->draft_msg));
836 if (info->transport_account)
837 g_object_unref (G_OBJECT(info->transport_account));
838 g_slice_free (SaveToDraftsInfo, info);
840 modest_mail_operation_notify_end (self);
844 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
845 TnyTransportAccount *transport_account,
847 ModestMsgEditWindow *edit_window,
848 const gchar *from, const gchar *to,
849 const gchar *cc, const gchar *bcc,
850 const gchar *subject, const gchar *plain_body,
851 const gchar *html_body,
852 const GList *attachments_list,
853 TnyHeaderFlags priority_flags)
855 ModestMailOperationPrivate *priv = NULL;
856 SaveToDraftsInfo *info = NULL;
858 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
859 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
861 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
863 /* Get account and set it into mail_operation */
864 priv->account = g_object_ref (transport_account);
866 info = g_slice_new0 (SaveToDraftsInfo);
867 info->transport_account = g_object_ref (transport_account);
868 info->draft_msg = draft_msg;
870 g_object_ref (draft_msg);
871 info->edit_window = edit_window;
873 g_object_ref (edit_window);
875 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
876 attachments_list, priority_flags,
877 modest_mail_operation_save_to_drafts_cb, info);
883 ModestMailOperation *mail_op;
884 TnyStoreAccount *account;
885 TnyTransportAccount *transport_account;
888 gchar *retrieve_type;
890 UpdateAccountCallback callback;
897 ModestMailOperation *mail_op;
898 TnyMimePart *mime_part;
900 GetMimePartSizeCallback callback;
902 } GetMimePartSizeInfo;
904 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
905 /* We use this folder observer to track the headers that have been
906 * added to a folder */
909 TnyList *new_headers;
910 } InternalFolderObserver;
914 } InternalFolderObserverClass;
916 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
918 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
919 internal_folder_observer,
921 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
925 foreach_add_item (gpointer header, gpointer user_data)
927 tny_list_prepend (TNY_LIST (user_data),
928 g_object_ref (G_OBJECT (header)));
931 /* This is the method that looks for new messages in a folder */
933 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
935 InternalFolderObserver *derived = (InternalFolderObserver *)self;
937 TnyFolderChangeChanged changed;
939 changed = tny_folder_change_get_changed (change);
941 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
944 /* Get added headers */
945 list = tny_simple_list_new ();
946 tny_folder_change_get_added_headers (change, list);
948 /* Add them to the folder observer */
949 tny_list_foreach (list, foreach_add_item,
950 derived->new_headers);
952 g_object_unref (G_OBJECT (list));
957 internal_folder_observer_init (InternalFolderObserver *self)
959 self->new_headers = tny_simple_list_new ();
962 internal_folder_observer_finalize (GObject *object)
964 InternalFolderObserver *self;
966 self = (InternalFolderObserver *) object;
967 g_object_unref (self->new_headers);
969 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
972 tny_folder_observer_init (TnyFolderObserverIface *iface)
974 iface->update_func = internal_folder_observer_update;
977 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
979 GObjectClass *object_class;
981 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
982 object_class = (GObjectClass*) klass;
983 object_class->finalize = internal_folder_observer_finalize;
989 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
992 TnyList *folders = tny_simple_list_new ();
994 tny_folder_store_get_folders (store, folders, query, NULL);
995 iter = tny_list_create_iterator (folders);
997 while (!tny_iterator_is_done (iter)) {
999 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1001 tny_list_prepend (all_folders, G_OBJECT (folder));
1002 recurse_folders (folder, query, all_folders);
1003 g_object_unref (G_OBJECT (folder));
1005 tny_iterator_next (iter);
1007 g_object_unref (G_OBJECT (iter));
1008 g_object_unref (G_OBJECT (folders));
1012 * Issues the "progress-changed" signal. The timer won't be removed,
1013 * so you must call g_source_remove to stop the signal emission
1016 idle_notify_progress (gpointer data)
1018 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1019 ModestMailOperationState *state;
1021 state = modest_mail_operation_clone_state (mail_op);
1022 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1023 g_slice_free (ModestMailOperationState, state);
1029 * Issues the "progress-changed" signal and removes the timer. It uses
1030 * a lock to ensure that the progress information of the mail
1031 * operation is not modified while there are notifications pending
1034 idle_notify_progress_once (gpointer data)
1038 pair = (ModestPair *) data;
1040 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1042 /* Free the state and the reference to the mail operation */
1043 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1044 g_object_unref (pair->first);
1050 * Used to notify the queue from the main
1051 * loop. We call it inside an idle call to achieve that
1054 idle_notify_queue (gpointer data)
1056 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1058 /* Do not need to block, the notify end will do it for us */
1059 modest_mail_operation_notify_end (mail_op);
1060 g_object_unref (mail_op);
1066 compare_headers_by_date (gconstpointer a,
1069 TnyHeader **header1, **header2;
1070 time_t sent1, sent2;
1072 header1 = (TnyHeader **) a;
1073 header2 = (TnyHeader **) b;
1075 sent1 = tny_header_get_date_sent (*header1);
1076 sent2 = tny_header_get_date_sent (*header2);
1078 /* We want the most recent ones (greater time_t) at the
1087 set_last_updated_idle (gpointer data)
1089 gdk_threads_enter ();
1091 /* It does not matter if the time is not exactly the same than
1092 the time when this idle was called, it's just an
1093 approximation and it won't be very different */
1094 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1096 MODEST_ACCOUNT_LAST_UPDATED,
1100 gdk_threads_leave ();
1106 idle_update_account_cb (gpointer data)
1108 UpdateAccountInfo *idle_info;
1110 idle_info = (UpdateAccountInfo *) data;
1112 gdk_threads_enter ();
1113 idle_info->callback (idle_info->mail_op,
1114 idle_info->new_headers,
1115 idle_info->user_data);
1116 gdk_threads_leave ();
1119 g_object_unref (idle_info->mail_op);
1127 update_account_thread (gpointer thr_user_data)
1129 static gboolean first_time = TRUE;
1130 UpdateAccountInfo *info;
1131 TnyList *all_folders = NULL;
1132 GPtrArray *new_headers = NULL;
1133 TnyIterator *iter = NULL;
1134 TnyFolderStoreQuery *query = NULL;
1135 ModestMailOperationPrivate *priv = NULL;
1136 ModestTnySendQueue *send_queue = NULL;
1138 info = (UpdateAccountInfo *) thr_user_data;
1139 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1141 /* Get account and set it into mail_operation */
1142 priv->account = g_object_ref (info->account);
1145 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
1146 * show any updates unless we do that
1148 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
1149 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1151 /* Get all the folders. We can do it synchronously because
1152 we're already running in a different thread than the UI */
1153 all_folders = tny_simple_list_new ();
1154 query = tny_folder_store_query_new ();
1155 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1156 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1161 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1165 iter = tny_list_create_iterator (all_folders);
1166 while (!tny_iterator_is_done (iter)) {
1167 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1169 recurse_folders (folder, query, all_folders);
1170 tny_iterator_next (iter);
1172 g_object_unref (G_OBJECT (iter));
1174 /* Update status and notify. We need to call the notification
1175 with a source function in order to call it from the main
1176 loop. We need that in order not to get into trouble with
1177 Gtk+. We use a timeout in order to provide more status
1178 information, because the sync tinymail call does not
1179 provide it for the moment */
1180 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1182 /* Refresh folders */
1183 new_headers = g_ptr_array_new ();
1184 iter = tny_list_create_iterator (all_folders);
1186 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
1188 InternalFolderObserver *observer;
1189 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1191 /* Refresh the folder */
1192 /* Our observer receives notification of new emails during folder refreshes,
1193 * so we can use observer->new_headers.
1195 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1196 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1198 /* This gets the status information (headers) from the server.
1199 * We use the blocking version, because we are already in a separate
1203 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1204 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1207 /* If the retrieve type is full messages, refresh and get the messages */
1208 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1210 iter = tny_list_create_iterator (observer->new_headers);
1211 while (!tny_iterator_is_done (iter)) {
1212 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1214 /* Apply per-message size limits */
1215 if (tny_header_get_message_size (header) < info->max_size)
1216 g_ptr_array_add (new_headers, g_object_ref (header));
1218 g_object_unref (header);
1219 tny_iterator_next (iter);
1221 g_object_unref (iter);
1223 /* We do not need to do it the first time
1224 because it's automatically done by the tree
1226 if (G_UNLIKELY (!first_time))
1227 tny_folder_poke_status (TNY_FOLDER (folder));
1229 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1230 g_object_unref (observer);
1233 g_object_unref (G_OBJECT (folder));
1236 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1240 tny_iterator_next (iter);
1243 did_a_cancel = FALSE;
1245 g_object_unref (G_OBJECT (iter));
1246 g_source_remove (timeout);
1248 if (new_headers->len > 0) {
1252 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1254 /* Apply message count limit */
1255 /* If the number of messages exceeds the maximum, ask the
1256 * user to download them all,
1257 * as per the UI spec "Retrieval Limits" section in 4.4:
1259 if (new_headers->len > info->retrieve_limit) {
1260 /* TODO: Ask the user, instead of just
1262 * mail_nc_msg_count_limit_exceeded, with 'Get
1263 * all' and 'Newest only' buttons. */
1264 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1265 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1266 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1267 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1268 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1273 priv->total = MIN (new_headers->len, info->retrieve_limit);
1274 while (msg_num < priv->total) {
1276 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1277 TnyFolder *folder = tny_header_get_folder (header);
1278 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1279 ModestMailOperationState *state;
1283 /* We can not just use the mail operation because the
1284 values of done and total could change before the
1286 state = modest_mail_operation_clone_state (info->mail_op);
1287 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1288 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1289 pair, (GDestroyNotify) modest_pair_free);
1291 g_object_unref (msg);
1292 g_object_unref (folder);
1296 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1297 g_ptr_array_free (new_headers, FALSE);
1300 /* Perform send (if operation was not cancelled) */
1301 if (did_a_cancel) goto out;
1302 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1305 if (priv->account != NULL)
1306 g_object_unref (priv->account);
1307 priv->account = g_object_ref (info->transport_account);
1309 send_queue = modest_runtime_get_send_queue (info->transport_account);
1311 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1312 modest_tny_send_queue_try_to_send (send_queue);
1313 /* g_source_remove (timeout); */
1315 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1316 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1317 "cannot create a send queue for %s\n",
1318 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1319 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1322 /* Check if the operation was a success */
1324 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1326 /* Update the last updated key */
1327 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1328 set_last_updated_idle,
1329 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1330 (GDestroyNotify) g_free);
1335 if (info->callback) {
1336 UpdateAccountInfo *idle_info;
1338 /* This thread is not in the main lock */
1339 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1340 idle_info->mail_op = g_object_ref (info->mail_op);
1341 idle_info->new_headers = (new_headers) ? new_headers->len : 0;
1342 idle_info->callback = info->callback;
1343 g_idle_add (idle_update_account_cb, idle_info);
1346 /* Notify about operation end. Note that the info could be
1347 freed before this idle happens, but the mail operation will
1349 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1352 g_object_unref (query);
1353 g_object_unref (all_folders);
1354 g_object_unref (info->account);
1355 g_object_unref (info->transport_account);
1356 g_free (info->retrieve_type);
1357 g_slice_free (UpdateAccountInfo, info);
1365 modest_mail_operation_update_account (ModestMailOperation *self,
1366 const gchar *account_name,
1367 UpdateAccountCallback callback,
1371 UpdateAccountInfo *info;
1372 ModestMailOperationPrivate *priv;
1373 ModestAccountMgr *mgr;
1374 TnyStoreAccount *modest_account;
1375 TnyTransportAccount *transport_account;
1377 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1378 g_return_val_if_fail (account_name, FALSE);
1380 /* Init mail operation. Set total and done to 0, and do not
1381 update them, this way the progress objects will know that
1382 we have no clue about the number of the objects */
1383 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1386 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1388 /* Make sure that we have a connection, and request one
1390 * TODO: Is there some way to trigger this for every attempt to
1391 * use the network? */
1392 if (!modest_platform_connect_and_wait (NULL))
1395 /* Get the Modest account */
1396 modest_account = (TnyStoreAccount *)
1397 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1399 TNY_ACCOUNT_TYPE_STORE);
1401 if (!modest_account) {
1402 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1403 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1404 "cannot get tny store account for %s\n", account_name);
1409 /* Get the transport account, we can not do it in the thread
1410 due to some problems with dbus */
1411 transport_account = (TnyTransportAccount *)
1412 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1414 if (!transport_account) {
1415 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1416 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1417 "cannot get tny transport account for %s\n", account_name);
1421 /* Create the helper object */
1422 info = g_slice_new (UpdateAccountInfo);
1423 info->mail_op = self;
1424 info->account = modest_account;
1425 info->transport_account = transport_account;
1426 info->callback = callback;
1427 info->user_data = user_data;
1429 /* Get the message size limit */
1430 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1431 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1432 if (info->max_size == 0)
1433 info->max_size = G_MAXINT;
1435 info->max_size = info->max_size * KB;
1437 /* Get per-account retrieval type */
1438 mgr = modest_runtime_get_account_mgr ();
1439 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1440 MODEST_ACCOUNT_RETRIEVE, FALSE);
1442 /* Get per-account message amount retrieval limit */
1443 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1444 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1445 if (info->retrieve_limit == 0)
1446 info->retrieve_limit = G_MAXINT;
1448 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1450 /* Set account busy */
1451 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1452 priv->account_name = g_strdup(account_name);
1454 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1459 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1461 callback (self, 0, user_data);
1462 modest_mail_operation_notify_end (self);
1466 /* ******************************************************************* */
1467 /* ************************** STORE ACTIONS ************************* */
1468 /* ******************************************************************* */
1472 modest_mail_operation_create_folder (ModestMailOperation *self,
1473 TnyFolderStore *parent,
1476 ModestMailOperationPrivate *priv;
1477 TnyFolder *new_folder = NULL;
1479 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1480 g_return_val_if_fail (name, NULL);
1482 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1485 if (TNY_IS_FOLDER (parent)) {
1486 /* Check folder rules */
1487 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1488 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1489 /* Set status failed and set an error */
1490 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1491 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1492 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1493 _("mail_in_ui_folder_create_error"));
1497 if (!strcmp (name, " ") || strchr (name, '/')) {
1498 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1499 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1500 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1501 _("mail_in_ui_folder_create_error"));
1505 /* Create the folder */
1506 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1507 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1509 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1512 /* Notify about operation end */
1513 modest_mail_operation_notify_end (self);
1519 modest_mail_operation_remove_folder (ModestMailOperation *self,
1521 gboolean remove_to_trash)
1523 TnyAccount *account;
1524 ModestMailOperationPrivate *priv;
1525 ModestTnyFolderRules rules;
1527 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1528 g_return_if_fail (TNY_IS_FOLDER (folder));
1530 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1532 /* Check folder rules */
1533 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1534 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1535 /* Set status failed and set an error */
1536 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1537 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1538 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1539 _("mail_in_ui_folder_delete_error"));
1543 /* Get the account */
1544 account = modest_tny_folder_get_account (folder);
1545 priv->account = g_object_ref(account);
1547 /* Delete folder or move to trash */
1548 if (remove_to_trash) {
1549 TnyFolder *trash_folder = NULL;
1550 trash_folder = modest_tny_account_get_special_folder (account,
1551 TNY_FOLDER_TYPE_TRASH);
1552 /* TODO: error_handling */
1553 modest_mail_operation_xfer_folder (self, folder,
1554 TNY_FOLDER_STORE (trash_folder),
1557 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1559 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1560 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1563 g_object_unref (G_OBJECT (parent));
1565 g_object_unref (G_OBJECT (account));
1568 /* Notify about operation end */
1569 modest_mail_operation_notify_end (self);
1573 transfer_folder_status_cb (GObject *obj,
1577 ModestMailOperation *self;
1578 ModestMailOperationPrivate *priv;
1579 ModestMailOperationState *state;
1580 XFerMsgAsyncHelper *helper;
1582 g_return_if_fail (status != NULL);
1583 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1585 helper = (XFerMsgAsyncHelper *) user_data;
1586 g_return_if_fail (helper != NULL);
1588 self = helper->mail_op;
1589 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1591 priv->done = status->position;
1592 priv->total = status->of_total;
1594 state = modest_mail_operation_clone_state (self);
1595 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1596 g_slice_free (ModestMailOperationState, state);
1601 transfer_folder_cb (TnyFolder *folder,
1602 TnyFolderStore *into,
1604 TnyFolder *new_folder,
1608 XFerMsgAsyncHelper *helper;
1609 ModestMailOperation *self = NULL;
1610 ModestMailOperationPrivate *priv = NULL;
1612 helper = (XFerMsgAsyncHelper *) user_data;
1613 g_return_if_fail (helper != NULL);
1615 self = helper->mail_op;
1616 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1619 priv->error = g_error_copy (*err);
1621 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1622 } else if (cancelled) {
1623 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1624 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1625 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1626 _("Transference of %s was cancelled."),
1627 tny_folder_get_name (folder));
1630 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1633 /* Notify about operation end */
1634 modest_mail_operation_notify_end (self);
1636 /* If user defined callback function was defined, call it */
1637 if (helper->user_callback) {
1638 gdk_threads_enter ();
1639 helper->user_callback (priv->source, helper->user_data);
1640 gdk_threads_leave ();
1644 g_object_unref (helper->mail_op);
1645 g_slice_free (XFerMsgAsyncHelper, helper);
1646 g_object_unref (folder);
1647 g_object_unref (into);
1651 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1653 TnyFolderStore *parent,
1654 gboolean delete_original,
1655 XferMsgsAsynUserCallback user_callback,
1658 ModestMailOperationPrivate *priv = NULL;
1659 ModestTnyFolderRules parent_rules = 0, rules;
1660 XFerMsgAsyncHelper *helper = NULL;
1662 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1663 g_return_if_fail (TNY_IS_FOLDER (folder));
1665 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1667 /* Get account and set it into mail_operation */
1668 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1669 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1671 /* Get folder rules */
1672 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1673 if (TNY_IS_FOLDER (parent))
1674 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1676 /* The moveable restriction is applied also to copy operation */
1677 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1678 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1679 /* Set status failed and set an error */
1680 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1681 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1682 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1683 _("mail_in_ui_folder_move_target_error"));
1685 /* Notify the queue */
1686 modest_mail_operation_notify_end (self);
1687 } else if (TNY_IS_FOLDER (parent) &&
1688 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1689 /* Set status failed and set an error */
1690 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1691 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1692 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1693 _("FIXME: parent folder does not accept new folders"));
1695 /* Notify the queue */
1696 modest_mail_operation_notify_end (self);
1698 /* Pick references for async calls */
1699 g_object_ref (folder);
1700 g_object_ref (parent);
1702 /* Create the helper */
1703 helper = g_slice_new0 (XFerMsgAsyncHelper);
1704 helper->mail_op = g_object_ref(self);
1705 helper->dest_folder = NULL;
1706 helper->headers = NULL;
1707 helper->user_callback = user_callback;
1708 helper->user_data = user_data;
1710 /* Move/Copy folder */
1711 tny_folder_copy_async (folder,
1713 tny_folder_get_name (folder),
1716 transfer_folder_status_cb,
1723 modest_mail_operation_rename_folder (ModestMailOperation *self,
1727 ModestMailOperationPrivate *priv;
1728 ModestTnyFolderRules rules;
1729 XFerMsgAsyncHelper *helper;
1731 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1732 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1733 g_return_if_fail (name);
1735 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1737 /* Get account and set it into mail_operation */
1738 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1740 /* Check folder rules */
1741 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1742 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1743 /* Set status failed and set an error */
1744 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1745 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1746 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1747 _("FIXME: unable to rename"));
1749 /* Notify about operation end */
1750 modest_mail_operation_notify_end (self);
1751 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1752 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1753 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1754 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1755 _("FIXME: unable to rename"));
1756 /* Notify about operation end */
1757 modest_mail_operation_notify_end (self);
1759 TnyFolderStore *into;
1761 ModestHeaderView *v = (ModestHeaderView *) modest_main_window_get_child_widget (
1762 (ModestMainWindow *)modest_window_mgr_get_main_window (
1763 modest_runtime_get_window_mgr ()), MODEST_WIDGET_TYPE_HEADER_VIEW);
1765 /* Create the helper */
1766 helper = g_slice_new0 (XFerMsgAsyncHelper);
1767 helper->mail_op = g_object_ref(self);
1768 helper->dest_folder = NULL;
1769 helper->headers = NULL;
1770 helper->user_callback = NULL;
1771 helper->user_data = NULL;
1773 modest_header_view_clear (v);
1775 /* Rename. Camel handles folder subscription/unsubscription */
1776 into = tny_folder_get_folder_store (folder);
1777 tny_folder_copy_async (folder, into, name, TRUE,
1779 transfer_folder_status_cb,
1783 g_object_unref (into);
1787 /* ******************************************************************* */
1788 /* ************************** MSG ACTIONS ************************* */
1789 /* ******************************************************************* */
1791 void modest_mail_operation_get_msg (ModestMailOperation *self,
1793 GetMsgAsyncUserCallback user_callback,
1796 GetMsgAsyncHelper *helper = NULL;
1798 ModestMailOperationPrivate *priv;
1800 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1801 g_return_if_fail (TNY_IS_HEADER (header));
1803 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1804 folder = tny_header_get_folder (header);
1806 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1808 /* Get message from folder */
1810 /* Get account and set it into mail_operation */
1811 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1813 helper = g_slice_new0 (GetMsgAsyncHelper);
1814 helper->mail_op = self;
1815 helper->user_callback = user_callback;
1816 helper->user_data = user_data;
1817 helper->header = g_object_ref (header);
1819 // The callback's reference so that the mail op is not
1820 // finalized until the async operation is completed even if
1821 // the user canceled the request meanwhile.
1822 g_object_ref (G_OBJECT (helper->mail_op));
1824 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1826 g_object_unref (G_OBJECT (folder));
1828 /* Set status failed and set an error */
1829 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1830 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1831 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1832 _("Error trying to get a message. No folder found for header"));
1834 /* Notify the queue */
1835 modest_mail_operation_notify_end (self);
1840 idle_get_mime_part_size_cb (gpointer userdata)
1842 GetMimePartSizeInfo *idle_info;
1844 idle_info = (GetMimePartSizeInfo *) userdata;
1846 gdk_threads_enter ();
1847 idle_info->callback (idle_info->mail_op,
1849 idle_info->userdata);
1850 gdk_threads_leave ();
1852 g_object_unref (idle_info->mail_op);
1853 g_slice_free (GetMimePartSizeInfo, idle_info);
1859 get_mime_part_size_thread (gpointer thr_user_data)
1861 GetMimePartSizeInfo *info;
1862 gchar read_buffer[GET_SIZE_BUFFER_SIZE];
1866 ModestMailOperationPrivate *priv;
1868 info = (GetMimePartSizeInfo *) thr_user_data;
1869 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1871 stream = tny_camel_mem_stream_new ();
1872 tny_mime_part_decode_to_stream (info->mime_part, stream);
1873 tny_stream_reset (stream);
1874 if (tny_stream_is_eos (stream)) {
1875 tny_stream_close (stream);
1876 stream = tny_mime_part_get_stream (info->mime_part);
1879 while (!tny_stream_is_eos (stream)) {
1880 readed_size = tny_stream_read (stream, read_buffer, GET_SIZE_BUFFER_SIZE);
1881 total += readed_size;
1884 if (info->callback) {
1885 GetMimePartSizeInfo *idle_info;
1887 idle_info = g_slice_new0 (GetMimePartSizeInfo);
1888 idle_info->mail_op = g_object_ref (info->mail_op);
1889 idle_info->size = total;
1890 idle_info->callback = info->callback;
1891 idle_info->userdata = info->userdata;
1892 g_idle_add (idle_get_mime_part_size_cb, idle_info);
1895 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1897 g_object_unref (info->mail_op);
1898 g_object_unref (stream);
1899 g_object_unref (info->mime_part);
1900 g_slice_free (GetMimePartSizeInfo, info);
1906 modest_mail_operation_get_mime_part_size (ModestMailOperation *self,
1908 GetMimePartSizeCallback user_callback,
1910 GDestroyNotify notify)
1912 GetMimePartSizeInfo *info;
1913 ModestMailOperationPrivate *priv;
1916 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1917 g_return_if_fail (TNY_IS_MIME_PART (part));
1919 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1921 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1922 info = g_slice_new0 (GetMimePartSizeInfo);
1923 info->mail_op = g_object_ref (self);
1924 info->mime_part = g_object_ref (part);
1925 info->callback = user_callback;
1926 info->userdata = user_data;
1928 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
1933 get_msg_cb (TnyFolder *folder,
1939 GetMsgAsyncHelper *helper = NULL;
1940 ModestMailOperation *self = NULL;
1941 ModestMailOperationPrivate *priv = NULL;
1943 helper = (GetMsgAsyncHelper *) user_data;
1944 g_return_if_fail (helper != NULL);
1945 self = helper->mail_op;
1946 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1947 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1949 /* Check errors and cancel */
1951 priv->error = g_error_copy (*error);
1952 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1953 } else if (cancelled) {
1954 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1955 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1956 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1957 _("Error trying to refresh the contents of %s"),
1958 tny_folder_get_name (folder));
1960 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1963 /* If user defined callback function was defined, call it even
1964 if the operation failed*/
1965 if (helper->user_callback) {
1966 /* This callback is called into an iddle by tinymail,
1967 and idles are not in the main lock */
1968 gdk_threads_enter ();
1969 helper->user_callback (self, helper->header, msg, helper->user_data);
1970 gdk_threads_leave ();
1973 /* Notify about operation end */
1974 modest_mail_operation_notify_end (self);
1976 g_object_unref (helper->mail_op);
1977 g_object_unref (helper->header);
1978 g_slice_free (GetMsgAsyncHelper, helper);
1983 get_msg_status_cb (GObject *obj,
1987 GetMsgAsyncHelper *helper = NULL;
1988 ModestMailOperation *self;
1989 ModestMailOperationPrivate *priv;
1990 ModestMailOperationState *state;
1992 g_return_if_fail (status != NULL);
1993 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1995 helper = (GetMsgAsyncHelper *) user_data;
1996 g_return_if_fail (helper != NULL);
1998 self = helper->mail_op;
1999 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2001 if(priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2002 TnyFolder *folder = tny_header_get_folder (helper->header);
2004 TnyAccount *account;
2005 account = tny_folder_get_account (folder);
2007 tny_account_cancel (account);
2008 g_object_unref (account);
2010 g_object_unref (folder);
2019 state = modest_mail_operation_clone_state (self);
2020 state->bytes_done = status->position;
2021 state->bytes_total = status->of_total;
2022 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2023 g_slice_free (ModestMailOperationState, state);
2026 /****************************************************/
2028 ModestMailOperation *mail_op;
2030 GetMsgAsyncUserCallback user_callback;
2032 GDestroyNotify notify;
2036 GetMsgAsyncUserCallback user_callback;
2040 ModestMailOperation *mail_op;
2041 } NotifyGetMsgsInfo;
2045 * Used by get_msgs_full_thread to call the user_callback for each
2046 * message that has been read
2049 notify_get_msgs_full (gpointer data)
2051 NotifyGetMsgsInfo *info;
2053 info = (NotifyGetMsgsInfo *) data;
2055 /* Call the user callback. Idles are not in the main lock, so
2057 gdk_threads_enter ();
2058 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2059 gdk_threads_leave ();
2061 g_slice_free (NotifyGetMsgsInfo, info);
2067 * Used by get_msgs_full_thread to free al the thread resources and to
2068 * call the destroy function for the passed user_data
2071 get_msgs_full_destroyer (gpointer data)
2073 GetFullMsgsInfo *info;
2075 info = (GetFullMsgsInfo *) data;
2078 gdk_threads_enter ();
2079 info->notify (info->user_data);
2080 gdk_threads_leave ();
2084 g_object_unref (info->headers);
2085 g_slice_free (GetFullMsgsInfo, info);
2091 get_msgs_full_thread (gpointer thr_user_data)
2093 GetFullMsgsInfo *info;
2094 ModestMailOperationPrivate *priv = NULL;
2095 TnyIterator *iter = NULL;
2097 info = (GetFullMsgsInfo *) thr_user_data;
2098 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2100 iter = tny_list_create_iterator (info->headers);
2101 while (!tny_iterator_is_done (iter)) {
2105 header = TNY_HEADER (tny_iterator_get_current (iter));
2106 folder = tny_header_get_folder (header);
2108 /* Get message from folder */
2111 /* The callback will call it per each header */
2112 msg = tny_folder_get_msg (folder, header, &(priv->error));
2115 ModestMailOperationState *state;
2120 /* notify progress */
2121 state = modest_mail_operation_clone_state (info->mail_op);
2122 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2123 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2124 pair, (GDestroyNotify) modest_pair_free);
2126 /* The callback is the responsible for
2127 freeing the message */
2128 if (info->user_callback) {
2129 NotifyGetMsgsInfo *info_notify;
2130 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2131 info_notify->user_callback = info->user_callback;
2132 info_notify->mail_op = info->mail_op;
2133 info_notify->header = g_object_ref (header);
2134 info_notify->msg = g_object_ref (msg);
2135 info_notify->user_data = info->user_data;
2136 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2137 notify_get_msgs_full,
2140 g_object_unref (msg);
2143 /* Set status failed and set an error */
2144 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2145 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2146 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2147 "Error trying to get a message. No folder found for header");
2149 g_object_unref (header);
2150 tny_iterator_next (iter);
2153 /* Set operation status */
2154 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2155 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2157 /* Notify about operation end */
2158 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2160 /* Free thread resources. Will be called after all previous idles */
2161 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2167 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2168 TnyList *header_list,
2169 GetMsgAsyncUserCallback user_callback,
2171 GDestroyNotify notify)
2173 TnyHeader *header = NULL;
2174 TnyFolder *folder = NULL;
2176 ModestMailOperationPrivate *priv = NULL;
2177 GetFullMsgsInfo *info = NULL;
2178 gboolean size_ok = TRUE;
2180 TnyIterator *iter = NULL;
2182 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2184 /* Init mail operation */
2185 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2186 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2188 priv->total = tny_list_get_length(header_list);
2190 /* Get account and set it into mail_operation */
2191 if (tny_list_get_length (header_list) >= 1) {
2192 iter = tny_list_create_iterator (header_list);
2193 header = TNY_HEADER (tny_iterator_get_current (iter));
2194 folder = tny_header_get_folder (header);
2195 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2196 g_object_unref (header);
2197 g_object_unref (folder);
2199 if (tny_list_get_length (header_list) == 1) {
2200 g_object_unref (iter);
2205 /* Get msg size limit */
2206 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2207 MODEST_CONF_MSG_SIZE_LIMIT,
2210 g_clear_error (&(priv->error));
2211 max_size = G_MAXINT;
2213 max_size = max_size * KB;
2216 /* Check message size limits. If there is only one message
2217 always retrieve it */
2219 while (!tny_iterator_is_done (iter) && size_ok) {
2220 header = TNY_HEADER (tny_iterator_get_current (iter));
2221 if (tny_header_get_message_size (header) >= max_size)
2223 g_object_unref (header);
2224 tny_iterator_next (iter);
2226 g_object_unref (iter);
2230 /* Create the info */
2231 info = g_slice_new0 (GetFullMsgsInfo);
2232 info->mail_op = self;
2233 info->user_callback = user_callback;
2234 info->user_data = user_data;
2235 info->headers = g_object_ref (header_list);
2236 info->notify = notify;
2238 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2240 /* Set status failed and set an error */
2241 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2242 /* FIXME: the error msg is different for pop */
2243 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2244 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2245 _("emev_ni_ui_imap_msg_size_exceed_error"));
2246 /* Remove from queue and free resources */
2247 modest_mail_operation_notify_end (self);
2255 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2256 gboolean remove_to_trash /*ignored*/)
2259 ModestMailOperationPrivate *priv;
2261 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2262 g_return_if_fail (TNY_IS_HEADER (header));
2264 if (remove_to_trash)
2265 g_warning ("remove to trash is not implemented");
2267 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2268 folder = tny_header_get_folder (header);
2270 /* Get account and set it into mail_operation */
2271 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2273 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2276 tny_folder_remove_msg (folder, header, &(priv->error));
2278 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2279 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2281 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2282 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2283 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2284 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2287 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2293 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2295 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2298 g_object_unref (G_OBJECT (folder));
2300 /* Notify about operation end */
2301 modest_mail_operation_notify_end (self);
2305 transfer_msgs_status_cb (GObject *obj,
2309 XFerMsgAsyncHelper *helper = NULL;
2310 ModestMailOperation *self;
2311 ModestMailOperationPrivate *priv;
2312 ModestMailOperationState *state;
2315 g_return_if_fail (status != NULL);
2316 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2318 helper = (XFerMsgAsyncHelper *) user_data;
2319 g_return_if_fail (helper != NULL);
2321 self = helper->mail_op;
2322 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2324 priv->done = status->position;
2325 priv->total = status->of_total;
2327 state = modest_mail_operation_clone_state (self);
2328 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2329 g_slice_free (ModestMailOperationState, state);
2334 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2336 XFerMsgAsyncHelper *helper;
2337 ModestMailOperation *self;
2338 ModestMailOperationPrivate *priv;
2340 helper = (XFerMsgAsyncHelper *) user_data;
2341 self = helper->mail_op;
2343 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2346 priv->error = g_error_copy (*err);
2348 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2349 } else if (cancelled) {
2350 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2351 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2352 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2353 _("Error trying to refresh the contents of %s"),
2354 tny_folder_get_name (folder));
2357 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2360 /* Notify about operation end */
2361 modest_mail_operation_notify_end (self);
2363 /* If user defined callback function was defined, call it */
2364 if (helper->user_callback) {
2365 gdk_threads_enter ();
2366 helper->user_callback (priv->source, helper->user_data);
2367 gdk_threads_leave ();
2371 g_object_unref (helper->headers);
2372 g_object_unref (helper->dest_folder);
2373 g_object_unref (helper->mail_op);
2374 g_slice_free (XFerMsgAsyncHelper, helper);
2375 g_object_unref (folder);
2380 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2383 gboolean delete_original,
2384 XferMsgsAsynUserCallback user_callback,
2387 ModestMailOperationPrivate *priv;
2389 TnyFolder *src_folder;
2390 XFerMsgAsyncHelper *helper;
2392 ModestTnyFolderRules rules;
2393 const gchar *id1 = NULL;
2394 const gchar *id2 = NULL;
2395 gboolean same_folder = FALSE;
2397 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2398 g_return_if_fail (TNY_IS_LIST (headers));
2399 g_return_if_fail (TNY_IS_FOLDER (folder));
2401 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2404 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2406 /* Apply folder rules */
2407 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2408 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2409 /* Set status failed and set an error */
2410 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2411 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2412 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2413 _CS("ckct_ib_unable_to_paste_here"));
2414 /* Notify the queue */
2415 modest_mail_operation_notify_end (self);
2419 /* Get source folder */
2420 iter = tny_list_create_iterator (headers);
2421 header = TNY_HEADER (tny_iterator_get_current (iter));
2422 src_folder = tny_header_get_folder (header);
2423 g_object_unref (header);
2424 g_object_unref (iter);
2426 /* Check folder source and destination */
2427 id1 = tny_folder_get_id (src_folder);
2428 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2429 same_folder = !g_ascii_strcasecmp (id1, id2);
2431 /* Set status failed and set an error */
2432 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2433 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2434 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2435 _("mcen_ib_unable_to_copy_samefolder"));
2437 /* Notify the queue */
2438 modest_mail_operation_notify_end (self);
2441 g_object_unref (src_folder);
2445 /* Create the helper */
2446 helper = g_slice_new0 (XFerMsgAsyncHelper);
2447 helper->mail_op = g_object_ref(self);
2448 helper->dest_folder = g_object_ref(folder);
2449 helper->headers = g_object_ref(headers);
2450 helper->user_callback = user_callback;
2451 helper->user_data = user_data;
2453 /* Get account and set it into mail_operation */
2454 priv->account = modest_tny_folder_get_account (src_folder);
2456 /* Transfer messages */
2457 tny_folder_transfer_msgs_async (src_folder,
2462 transfer_msgs_status_cb,
2468 on_refresh_folder (TnyFolder *folder,
2473 RefreshAsyncHelper *helper = NULL;
2474 ModestMailOperation *self = NULL;
2475 ModestMailOperationPrivate *priv = NULL;
2477 helper = (RefreshAsyncHelper *) user_data;
2478 self = helper->mail_op;
2479 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2482 priv->error = g_error_copy (*error);
2483 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2488 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2489 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2490 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2491 _("Error trying to refresh the contents of %s"),
2492 tny_folder_get_name (folder));
2496 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2498 /* Call user defined callback, if it exists */
2499 if (helper->user_callback) {
2500 gdk_threads_enter ();
2501 helper->user_callback (self, folder, helper->user_data);
2502 gdk_threads_leave ();
2506 g_object_unref (helper->mail_op);
2507 g_slice_free (RefreshAsyncHelper, helper);
2508 g_object_unref (folder);
2510 /* Notify about operation end */
2511 modest_mail_operation_notify_end (self);
2515 on_refresh_folder_status_update (GObject *obj,
2519 RefreshAsyncHelper *helper = NULL;
2520 ModestMailOperation *self = NULL;
2521 ModestMailOperationPrivate *priv = NULL;
2522 ModestMailOperationState *state;
2524 g_return_if_fail (user_data != NULL);
2525 g_return_if_fail (status != NULL);
2526 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2528 helper = (RefreshAsyncHelper *) user_data;
2529 self = helper->mail_op;
2530 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2532 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2534 priv->done = status->position;
2535 priv->total = status->of_total;
2537 state = modest_mail_operation_clone_state (self);
2538 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2539 g_slice_free (ModestMailOperationState, state);
2543 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2545 RefreshAsyncUserCallback user_callback,
2548 ModestMailOperationPrivate *priv = NULL;
2549 RefreshAsyncHelper *helper = NULL;
2551 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2553 /* Pick a reference */
2554 g_object_ref (folder);
2556 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2558 /* Get account and set it into mail_operation */
2559 priv->account = modest_tny_folder_get_account (folder);
2561 /* Create the helper */
2562 helper = g_slice_new0 (RefreshAsyncHelper);
2563 helper->mail_op = g_object_ref(self);
2564 helper->user_callback = user_callback;
2565 helper->user_data = user_data;
2567 /* Refresh the folder. TODO: tinymail could issue a status
2568 updates before the callback call then this could happen. We
2569 must review the design */
2570 tny_folder_refresh_async (folder,
2572 on_refresh_folder_status_update,
2578 * It's used by the mail operation queue to notify the observers
2579 * attached to that signal that the operation finished. We need to use
2580 * that because tinymail does not give us the progress of a given
2581 * operation when it finishes (it directly calls the operation
2585 modest_mail_operation_notify_end (ModestMailOperation *self)
2587 ModestMailOperationState *state;
2588 ModestMailOperationPrivate *priv = NULL;
2590 g_return_if_fail (self);
2592 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2594 /* Set the account back to not busy */
2595 if (priv->account_name) {
2596 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2597 priv->account_name, FALSE);
2598 g_free(priv->account_name);
2599 priv->account_name = NULL;
2602 /* Notify the observers about the mail opertation end */
2603 state = modest_mail_operation_clone_state (self);
2604 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2605 g_slice_free (ModestMailOperationState, state);