1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-camel-pop-store-account.h>
38 #include <tny-camel-pop-folder.h>
39 #include <tny-camel-imap-folder.h>
40 #include <tny-camel-mem-stream.h>
41 #include <tny-simple-list.h>
42 #include <tny-send-queue.h>
43 #include <tny-status.h>
44 #include <tny-folder-observer.h>
45 #include <camel/camel-stream-mem.h>
46 #include <glib/gi18n.h>
47 #include "modest-platform.h"
48 #include <modest-tny-account.h>
49 #include <modest-tny-send-queue.h>
50 #include <modest-runtime.h>
51 #include "modest-text-utils.h"
52 #include "modest-tny-msg.h"
53 #include "modest-tny-folder.h"
54 #include "modest-tny-account-store.h"
55 #include "modest-tny-platform-factory.h"
56 #include "modest-marshal.h"
57 #include "modest-error.h"
58 #include "modest-mail-operation.h"
61 #define GET_SIZE_BUFFER_SIZE 128
64 * Remove all these #ifdef stuff when the tinymail's idle calls become
67 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
69 /* 'private'/'protected' functions */
70 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
71 static void modest_mail_operation_init (ModestMailOperation *obj);
72 static void modest_mail_operation_finalize (GObject *obj);
74 static void get_msg_cb (TnyFolder *folder,
80 static void get_msg_status_cb (GObject *obj,
84 static void modest_mail_operation_notify_end (ModestMailOperation *self);
86 enum _ModestMailOperationSignals
88 PROGRESS_CHANGED_SIGNAL,
93 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
94 struct _ModestMailOperationPrivate {
101 ErrorCheckingUserCallback error_checking;
102 gpointer error_checking_user_data;
103 ModestMailOperationStatus status;
104 ModestMailOperationTypeOperation op_type;
107 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
108 MODEST_TYPE_MAIL_OPERATION, \
109 ModestMailOperationPrivate))
111 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
112 priv->status = new_status;\
115 typedef struct _GetMsgAsyncHelper {
116 ModestMailOperation *mail_op;
118 GetMsgAsyncUserCallback user_callback;
122 typedef struct _RefreshAsyncHelper {
123 ModestMailOperation *mail_op;
124 RefreshAsyncUserCallback user_callback;
126 } RefreshAsyncHelper;
128 typedef struct _XFerMsgAsyncHelper
130 ModestMailOperation *mail_op;
132 TnyFolder *dest_folder;
133 XferMsgsAsynUserCallback user_callback;
135 } XFerMsgAsyncHelper;
137 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
141 static void modest_mail_operation_create_msg (ModestMailOperation *self,
142 const gchar *from, const gchar *to,
143 const gchar *cc, const gchar *bcc,
144 const gchar *subject, const gchar *plain_body,
145 const gchar *html_body, const GList *attachments_list,
146 TnyHeaderFlags priority_flags,
147 ModestMailOperationCreateMsgCallback callback,
150 static gboolean idle_notify_queue (gpointer data);
153 ModestMailOperation *mail_op;
161 GList *attachments_list;
162 TnyHeaderFlags priority_flags;
163 ModestMailOperationCreateMsgCallback callback;
169 ModestMailOperation *mail_op;
171 ModestMailOperationCreateMsgCallback callback;
176 static GObjectClass *parent_class = NULL;
178 static guint signals[NUM_SIGNALS] = {0};
181 modest_mail_operation_get_type (void)
183 static GType my_type = 0;
185 static const GTypeInfo my_info = {
186 sizeof(ModestMailOperationClass),
187 NULL, /* base init */
188 NULL, /* base finalize */
189 (GClassInitFunc) modest_mail_operation_class_init,
190 NULL, /* class finalize */
191 NULL, /* class data */
192 sizeof(ModestMailOperation),
194 (GInstanceInitFunc) modest_mail_operation_init,
197 my_type = g_type_register_static (G_TYPE_OBJECT,
198 "ModestMailOperation",
205 modest_mail_operation_class_init (ModestMailOperationClass *klass)
207 GObjectClass *gobject_class;
208 gobject_class = (GObjectClass*) klass;
210 parent_class = g_type_class_peek_parent (klass);
211 gobject_class->finalize = modest_mail_operation_finalize;
213 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
216 * ModestMailOperation::progress-changed
217 * @self: the #MailOperation that emits the signal
218 * @user_data: user data set when the signal handler was connected
220 * Emitted when the progress of a mail operation changes
222 signals[PROGRESS_CHANGED_SIGNAL] =
223 g_signal_new ("progress-changed",
224 G_TYPE_FROM_CLASS (gobject_class),
226 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
228 g_cclosure_marshal_VOID__POINTER,
229 G_TYPE_NONE, 1, G_TYPE_POINTER);
234 modest_mail_operation_init (ModestMailOperation *obj)
236 ModestMailOperationPrivate *priv;
238 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
240 priv->account = NULL;
241 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
242 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
247 priv->error_checking = NULL;
248 priv->error_checking_user_data = NULL;
252 modest_mail_operation_finalize (GObject *obj)
254 ModestMailOperationPrivate *priv;
256 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
261 g_error_free (priv->error);
265 g_object_unref (priv->source);
269 g_object_unref (priv->account);
270 priv->account = NULL;
274 G_OBJECT_CLASS(parent_class)->finalize (obj);
278 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
281 ModestMailOperation *obj;
282 ModestMailOperationPrivate *priv;
284 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
285 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
287 priv->op_type = op_type;
289 priv->source = g_object_ref(source);
295 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
297 ErrorCheckingUserCallback error_handler,
300 ModestMailOperation *obj;
301 ModestMailOperationPrivate *priv;
303 obj = modest_mail_operation_new (op_type, source);
304 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
306 g_return_val_if_fail (error_handler != NULL, obj);
307 priv->error_checking = error_handler;
313 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
315 ModestMailOperationPrivate *priv;
317 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
318 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
320 if (priv->error_checking != NULL)
321 priv->error_checking (self, priv->error_checking_user_data);
325 ModestMailOperationTypeOperation
326 modest_mail_operation_get_type_operation (ModestMailOperation *self)
328 ModestMailOperationPrivate *priv;
330 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
332 return priv->op_type;
336 modest_mail_operation_is_mine (ModestMailOperation *self,
339 ModestMailOperationPrivate *priv;
341 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
342 if (priv->source == NULL) return FALSE;
344 return priv->source == me;
348 modest_mail_operation_get_source (ModestMailOperation *self)
350 ModestMailOperationPrivate *priv;
352 g_return_val_if_fail (self, NULL);
354 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
356 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
360 return g_object_ref (priv->source);
363 ModestMailOperationStatus
364 modest_mail_operation_get_status (ModestMailOperation *self)
366 ModestMailOperationPrivate *priv;
368 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
369 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
370 MODEST_MAIL_OPERATION_STATUS_INVALID);
372 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
374 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
375 return MODEST_MAIL_OPERATION_STATUS_INVALID;
382 modest_mail_operation_get_error (ModestMailOperation *self)
384 ModestMailOperationPrivate *priv;
386 g_return_val_if_fail (self, NULL);
387 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
389 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
392 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
400 modest_mail_operation_cancel (ModestMailOperation *self)
402 ModestMailOperationPrivate *priv;
403 gboolean canceled = FALSE;
405 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
407 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
409 /* Note that if we call cancel with an already canceled mail
410 operation the progress changed signal won't be emitted */
411 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
415 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
417 /* Cancel the mail operation. We need to wrap it between this
418 start/stop operations to allow following calls to the
420 g_return_val_if_fail (priv->account, FALSE);
421 tny_account_cancel (priv->account);
427 modest_mail_operation_get_task_done (ModestMailOperation *self)
429 ModestMailOperationPrivate *priv;
431 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
433 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
438 modest_mail_operation_get_task_total (ModestMailOperation *self)
440 ModestMailOperationPrivate *priv;
442 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
444 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
449 modest_mail_operation_is_finished (ModestMailOperation *self)
451 ModestMailOperationPrivate *priv;
452 gboolean retval = FALSE;
454 if (!MODEST_IS_MAIL_OPERATION (self)) {
455 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
459 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
461 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
462 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
463 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
464 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
474 modest_mail_operation_get_id (ModestMailOperation *self)
476 ModestMailOperationPrivate *priv;
478 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
480 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
485 modest_mail_operation_set_id (ModestMailOperation *self,
488 ModestMailOperationPrivate *priv;
490 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
492 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
497 * Creates an image of the current state of a mail operation, the
498 * caller must free it
500 static ModestMailOperationState *
501 modest_mail_operation_clone_state (ModestMailOperation *self)
503 ModestMailOperationState *state;
504 ModestMailOperationPrivate *priv;
506 /* FIXME: this should be fixed properly
508 * in some cases, priv was NULL, so checking here to
511 g_return_val_if_fail (self, NULL);
512 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
513 g_return_val_if_fail (priv, NULL);
518 state = g_slice_new (ModestMailOperationState);
520 state->status = priv->status;
521 state->op_type = priv->op_type;
522 state->done = priv->done;
523 state->total = priv->total;
524 state->finished = modest_mail_operation_is_finished (self);
525 state->bytes_done = 0;
526 state->bytes_total = 0;
531 /* ******************************************************************* */
532 /* ************************** SEND ACTIONS ************************* */
533 /* ******************************************************************* */
536 modest_mail_operation_send_mail (ModestMailOperation *self,
537 TnyTransportAccount *transport_account,
540 TnySendQueue *send_queue = NULL;
541 ModestMailOperationPrivate *priv;
543 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
544 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
545 g_return_if_fail (TNY_IS_MSG (msg));
547 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
549 /* Get account and set it into mail_operation */
550 priv->account = g_object_ref (transport_account);
554 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
555 if (!TNY_IS_SEND_QUEUE(send_queue)) {
556 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
557 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
558 "modest: could not find send queue for account\n");
560 /* TODO: connect to the msg-sent in order to know when
561 the mail operation is finished */
562 tny_send_queue_add (send_queue, msg, &(priv->error));
563 /* TODO: we're setting always success, do the check in
565 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
568 /* TODO: do this in the handler of the "msg-sent"
569 signal.Notify about operation end */
570 modest_mail_operation_notify_end (self);
574 idle_create_msg_cb (gpointer idle_data)
576 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
578 gdk_threads_enter ();
579 info->callback (info->mail_op, info->msg, info->userdata);
580 gdk_threads_leave ();
581 g_object_unref (info->mail_op);
583 g_object_unref (info->msg);
584 g_slice_free (CreateMsgIdleInfo, info);
590 create_msg_thread (gpointer thread_data)
592 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
593 TnyMsg *new_msg = NULL;
594 ModestMailOperationPrivate *priv;
596 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
597 if (info->html_body == NULL) {
598 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
599 info->bcc, info->subject, info->plain_body,
600 info->attachments_list); /* FIXME: attachments */
602 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
603 info->bcc, info->subject, info->html_body,
604 info->plain_body, info->attachments_list);
609 /* Set priority flags in message */
610 header = tny_msg_get_header (new_msg);
611 if (info->priority_flags != 0)
612 tny_header_set_flags (header, info->priority_flags);
613 if (info->attachments_list != NULL) {
614 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
616 g_object_unref (G_OBJECT(header));
618 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
619 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
620 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
621 "modest: failed to create a new msg\n");
629 g_free (info->plain_body);
630 g_free (info->html_body);
631 g_free (info->subject);
632 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
633 g_list_free (info->attachments_list);
635 if (info->callback) {
636 CreateMsgIdleInfo *idle_info;
637 idle_info = g_slice_new0 (CreateMsgIdleInfo);
638 idle_info->mail_op = info->mail_op;
639 g_object_ref (info->mail_op);
640 idle_info->msg = new_msg;
642 g_object_ref (new_msg);
643 idle_info->callback = info->callback;
644 idle_info->userdata = info->userdata;
645 g_idle_add (idle_create_msg_cb, idle_info);
647 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
650 g_object_unref (info->mail_op);
651 g_slice_free (CreateMsgInfo, info);
656 modest_mail_operation_create_msg (ModestMailOperation *self,
657 const gchar *from, const gchar *to,
658 const gchar *cc, const gchar *bcc,
659 const gchar *subject, const gchar *plain_body,
660 const gchar *html_body,
661 const GList *attachments_list,
662 TnyHeaderFlags priority_flags,
663 ModestMailOperationCreateMsgCallback callback,
666 CreateMsgInfo *info = NULL;
668 info = g_slice_new0 (CreateMsgInfo);
669 info->mail_op = self;
672 info->from = g_strdup (from);
673 info->to = g_strdup (to);
674 info->cc = g_strdup (cc);
675 info->bcc = g_strdup (bcc);
676 info->subject = g_strdup (subject);
677 info->plain_body = g_strdup (plain_body);
678 info->html_body = g_strdup (html_body);
679 info->attachments_list = g_list_copy ((GList *) attachments_list);
680 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
681 info->priority_flags = priority_flags;
683 info->callback = callback;
684 info->userdata = userdata;
686 g_thread_create (create_msg_thread, info, FALSE, NULL);
691 TnyTransportAccount *transport_account;
696 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
700 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
708 /* Call mail operation */
709 modest_mail_operation_send_mail (self, info->transport_account, msg);
711 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
713 if (info->draft_msg != NULL) {
714 header = tny_msg_get_header (info->draft_msg);
715 /* Note: This can fail (with a warning) if the message is not really already in a folder,
716 * because this function requires it to have a UID. */
717 tny_folder_remove_msg (folder, header, NULL);
718 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
719 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
720 g_object_unref (header);
721 g_object_unref (folder);
727 g_object_unref (info->draft_msg);
728 if (info->transport_account)
729 g_object_unref (info->transport_account);
730 g_slice_free (SendNewMailInfo, info);
731 modest_mail_operation_notify_end (self);
735 modest_mail_operation_send_new_mail (ModestMailOperation *self,
736 TnyTransportAccount *transport_account,
738 const gchar *from, const gchar *to,
739 const gchar *cc, const gchar *bcc,
740 const gchar *subject, const gchar *plain_body,
741 const gchar *html_body,
742 const GList *attachments_list,
743 TnyHeaderFlags priority_flags)
745 ModestMailOperationPrivate *priv = NULL;
746 SendNewMailInfo *info;
748 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
749 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
751 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
753 /* Check parametters */
755 /* Set status failed and set an error */
756 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
757 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
758 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
759 _("Error trying to send a mail. You need to set at least one recipient"));
762 info = g_slice_new0 (SendNewMailInfo);
763 info->transport_account = transport_account;
764 if (transport_account)
765 g_object_ref (transport_account);
766 info->draft_msg = draft_msg;
768 g_object_ref (draft_msg);
769 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
770 attachments_list, priority_flags,
771 modest_mail_operation_send_new_mail_cb, info);
777 TnyTransportAccount *transport_account;
779 ModestMsgEditWindow *edit_window;
783 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
787 TnyFolder *folder = NULL;
788 TnyHeader *header = NULL;
789 ModestMailOperationPrivate *priv = NULL;
790 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
792 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
794 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
795 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
796 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
797 "modest: failed to create a new msg\n");
801 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
803 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
804 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
805 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
806 "modest: failed to create a new msg\n");
810 if (info->draft_msg != NULL) {
811 header = tny_msg_get_header (info->draft_msg);
812 /* Remove the old draft expunging it */
813 tny_folder_remove_msg (folder, header, NULL);
814 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
815 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
816 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
817 g_object_unref (header);
821 tny_folder_add_msg (folder, msg, &(priv->error));
824 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
826 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
828 if (info->edit_window)
829 modest_msg_edit_window_set_draft (info->edit_window, msg);
834 g_object_unref (G_OBJECT(folder));
835 if (info->edit_window)
836 g_object_unref (G_OBJECT(info->edit_window));
838 g_object_unref (G_OBJECT (info->draft_msg));
839 if (info->transport_account)
840 g_object_unref (G_OBJECT(info->transport_account));
841 g_slice_free (SaveToDraftsInfo, info);
843 modest_mail_operation_notify_end (self);
847 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
848 TnyTransportAccount *transport_account,
850 ModestMsgEditWindow *edit_window,
851 const gchar *from, const gchar *to,
852 const gchar *cc, const gchar *bcc,
853 const gchar *subject, const gchar *plain_body,
854 const gchar *html_body,
855 const GList *attachments_list,
856 TnyHeaderFlags priority_flags)
858 ModestMailOperationPrivate *priv = NULL;
859 SaveToDraftsInfo *info = NULL;
861 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
862 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
864 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
866 /* Get account and set it into mail_operation */
867 priv->account = g_object_ref (transport_account);
869 info = g_slice_new0 (SaveToDraftsInfo);
870 info->transport_account = g_object_ref (transport_account);
871 info->draft_msg = draft_msg;
873 g_object_ref (draft_msg);
874 info->edit_window = edit_window;
876 g_object_ref (edit_window);
878 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
879 attachments_list, priority_flags,
880 modest_mail_operation_save_to_drafts_cb, info);
886 ModestMailOperation *mail_op;
887 TnyStoreAccount *account;
888 TnyTransportAccount *transport_account;
891 gchar *retrieve_type;
893 UpdateAccountCallback callback;
900 ModestMailOperation *mail_op;
901 TnyMimePart *mime_part;
903 GetMimePartSizeCallback callback;
905 } GetMimePartSizeInfo;
907 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
908 /* We use this folder observer to track the headers that have been
909 * added to a folder */
912 TnyList *new_headers;
913 } InternalFolderObserver;
917 } InternalFolderObserverClass;
919 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
921 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
922 internal_folder_observer,
924 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
928 foreach_add_item (gpointer header, gpointer user_data)
930 tny_list_prepend (TNY_LIST (user_data),
931 g_object_ref (G_OBJECT (header)));
934 /* This is the method that looks for new messages in a folder */
936 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
938 InternalFolderObserver *derived = (InternalFolderObserver *)self;
940 TnyFolderChangeChanged changed;
942 changed = tny_folder_change_get_changed (change);
944 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
947 /* Get added headers */
948 list = tny_simple_list_new ();
949 tny_folder_change_get_added_headers (change, list);
951 /* Add them to the folder observer */
952 tny_list_foreach (list, foreach_add_item,
953 derived->new_headers);
955 g_object_unref (G_OBJECT (list));
960 internal_folder_observer_init (InternalFolderObserver *self)
962 self->new_headers = tny_simple_list_new ();
965 internal_folder_observer_finalize (GObject *object)
967 InternalFolderObserver *self;
969 self = (InternalFolderObserver *) object;
970 g_object_unref (self->new_headers);
972 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
975 tny_folder_observer_init (TnyFolderObserverIface *iface)
977 iface->update_func = internal_folder_observer_update;
980 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
982 GObjectClass *object_class;
984 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
985 object_class = (GObjectClass*) klass;
986 object_class->finalize = internal_folder_observer_finalize;
992 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
995 TnyList *folders = tny_simple_list_new ();
997 tny_folder_store_get_folders (store, folders, query, NULL);
998 iter = tny_list_create_iterator (folders);
1000 while (!tny_iterator_is_done (iter)) {
1002 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1004 tny_list_prepend (all_folders, G_OBJECT (folder));
1005 recurse_folders (folder, query, all_folders);
1006 g_object_unref (G_OBJECT (folder));
1009 tny_iterator_next (iter);
1011 g_object_unref (G_OBJECT (iter));
1012 g_object_unref (G_OBJECT (folders));
1016 * Issues the "progress-changed" signal. The timer won't be removed,
1017 * so you must call g_source_remove to stop the signal emission
1020 idle_notify_progress (gpointer data)
1022 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1023 ModestMailOperationState *state;
1025 state = modest_mail_operation_clone_state (mail_op);
1026 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1027 gdk_threads_enter ();
1029 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1030 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1031 gdk_threads_leave ();
1033 g_slice_free (ModestMailOperationState, state);
1039 * Issues the "progress-changed" signal and removes the timer. It uses
1040 * a lock to ensure that the progress information of the mail
1041 * operation is not modified while there are notifications pending
1044 idle_notify_progress_once (gpointer data)
1048 pair = (ModestPair *) data;
1050 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1051 gdk_threads_enter ();
1053 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1054 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1055 gdk_threads_leave ();
1058 /* Free the state and the reference to the mail operation */
1059 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1060 g_object_unref (pair->first);
1066 * Used to notify the queue from the main
1067 * loop. We call it inside an idle call to achieve that
1070 idle_notify_queue (gpointer data)
1072 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1074 /* Do not need to block, the notify end will do it for us */
1075 modest_mail_operation_notify_end (mail_op);
1076 g_object_unref (mail_op);
1082 compare_headers_by_date (gconstpointer a,
1085 TnyHeader **header1, **header2;
1086 time_t sent1, sent2;
1088 header1 = (TnyHeader **) a;
1089 header2 = (TnyHeader **) b;
1091 sent1 = tny_header_get_date_sent (*header1);
1092 sent2 = tny_header_get_date_sent (*header2);
1094 /* We want the most recent ones (greater time_t) at the
1103 set_last_updated_idle (gpointer data)
1105 gdk_threads_enter ();
1107 /* It does not matter if the time is not exactly the same than
1108 the time when this idle was called, it's just an
1109 approximation and it won't be very different */
1110 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1112 MODEST_ACCOUNT_LAST_UPDATED,
1116 gdk_threads_leave ();
1122 idle_update_account_cb (gpointer data)
1124 UpdateAccountInfo *idle_info;
1126 idle_info = (UpdateAccountInfo *) data;
1128 gdk_threads_enter ();
1129 idle_info->callback (idle_info->mail_op,
1130 idle_info->new_headers,
1131 idle_info->user_data);
1132 gdk_threads_leave ();
1135 g_object_unref (idle_info->mail_op);
1143 update_account_thread (gpointer thr_user_data)
1145 static gboolean first_time = TRUE;
1146 UpdateAccountInfo *info = NULL;
1147 TnyList *all_folders = NULL;
1148 GPtrArray *new_headers = NULL;
1149 TnyIterator *iter = NULL;
1150 TnyFolderStoreQuery *query = NULL;
1151 ModestMailOperationPrivate *priv = NULL;
1152 ModestTnySendQueue *send_queue = NULL;
1153 gint num_new_headers = 0;
1155 info = (UpdateAccountInfo *) thr_user_data;
1156 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1158 /* Get account and set it into mail_operation */
1159 priv->account = g_object_ref (info->account);
1162 * Previousl, we did this for POP3, to do a logout-login upon send/receive,
1163 * because many POP-servers (like Gmail) do not
1164 * show any updates unless we do that.
1165 * But that didn't work with gmail anyway,
1166 * and tinymail now takes care of this itself by disconnecting
1167 * automatically after using the connection.
1170 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT (priv->account))
1171 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1174 /* Get all the folders. We can do it synchronously because
1175 we're already running in a different thread than the UI */
1176 all_folders = tny_simple_list_new ();
1177 query = tny_folder_store_query_new ();
1178 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1179 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1184 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1188 iter = tny_list_create_iterator (all_folders);
1189 while (!tny_iterator_is_done (iter)) {
1190 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1192 recurse_folders (folder, query, all_folders);
1193 g_object_unref (folder);
1195 tny_iterator_next (iter);
1197 g_object_unref (G_OBJECT (iter));
1199 /* Update status and notify. We need to call the notification
1200 with a source function in order to call it from the main
1201 loop. We need that in order not to get into trouble with
1202 Gtk+. We use a timeout in order to provide more status
1203 information, because the sync tinymail call does not
1204 provide it for the moment */
1205 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1207 /* Refresh folders */
1208 num_new_headers = 0;
1209 new_headers = g_ptr_array_new ();
1210 iter = tny_list_create_iterator (all_folders);
1212 while (!tny_iterator_is_done (iter) && !priv->error &&
1213 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1215 InternalFolderObserver *observer;
1216 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1218 /* Refresh the folder */
1219 /* Our observer receives notification of new emails during folder refreshes,
1220 * so we can use observer->new_headers.
1222 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1223 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1225 /* This gets the status information (headers) from the server.
1226 * We use the blocking version, because we are already in a separate
1230 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1231 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1234 /* If the retrieve type is full messages, refresh and get the messages */
1235 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1237 iter = tny_list_create_iterator (observer->new_headers);
1238 while (!tny_iterator_is_done (iter)) {
1239 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1241 /* Apply per-message size limits */
1242 if (tny_header_get_message_size (header) < info->max_size)
1243 g_ptr_array_add (new_headers, g_object_ref (header));
1245 g_object_unref (header);
1246 tny_iterator_next (iter);
1248 g_object_unref (iter);
1250 /* We do not need to do it the first time
1251 because it's automatically done by the tree
1253 if (G_UNLIKELY (!first_time))
1254 tny_folder_poke_status (TNY_FOLDER (folder));
1256 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1257 g_object_unref (observer);
1261 g_object_unref (G_OBJECT (folder));
1264 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1266 tny_iterator_next (iter);
1269 g_object_unref (G_OBJECT (iter));
1270 g_source_remove (timeout);
1272 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1273 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1274 new_headers->len > 0) {
1278 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1280 /* Apply message count limit */
1281 /* If the number of messages exceeds the maximum, ask the
1282 * user to download them all,
1283 * as per the UI spec "Retrieval Limits" section in 4.4:
1285 if (new_headers->len > info->retrieve_limit) {
1286 /* TODO: Ask the user, instead of just
1288 * mail_nc_msg_count_limit_exceeded, with 'Get
1289 * all' and 'Newest only' buttons. */
1290 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1291 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1292 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1293 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1294 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1299 priv->total = MIN (new_headers->len, info->retrieve_limit);
1300 while (msg_num < priv->total) {
1302 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1303 TnyFolder *folder = tny_header_get_folder (header);
1304 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1305 ModestMailOperationState *state;
1309 /* We can not just use the mail operation because the
1310 values of done and total could change before the
1312 state = modest_mail_operation_clone_state (info->mail_op);
1313 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1314 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1315 pair, (GDestroyNotify) modest_pair_free);
1317 g_object_unref (msg);
1318 g_object_unref (folder);
1324 /* Get the number of new headers and free them */
1325 num_new_headers = new_headers->len;
1326 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1327 g_ptr_array_free (new_headers, FALSE);
1329 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1332 /* Perform send (if operation was not cancelled) */
1333 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1336 if (priv->account != NULL)
1337 g_object_unref (priv->account);
1338 priv->account = g_object_ref (info->transport_account);
1340 send_queue = modest_runtime_get_send_queue (info->transport_account);
1342 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1343 modest_tny_send_queue_try_to_send (send_queue);
1344 /* g_source_remove (timeout); */
1346 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1347 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1348 "cannot create a send queue for %s\n",
1349 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1350 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1353 /* Check if the operation was a success */
1355 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1357 /* Update the last updated key */
1358 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1359 set_last_updated_idle,
1360 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1361 (GDestroyNotify) g_free);
1366 if (info->callback) {
1367 UpdateAccountInfo *idle_info;
1369 /* This thread is not in the main lock */
1370 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1371 idle_info->mail_op = g_object_ref (info->mail_op);
1372 idle_info->new_headers = num_new_headers;
1373 idle_info->callback = info->callback;
1374 g_idle_add (idle_update_account_cb, idle_info);
1377 /* Notify about operation end. Note that the info could be
1378 freed before this idle happens, but the mail operation will
1380 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1383 g_object_unref (query);
1384 g_object_unref (all_folders);
1385 g_object_unref (info->account);
1386 g_object_unref (info->transport_account);
1387 g_free (info->retrieve_type);
1388 g_slice_free (UpdateAccountInfo, info);
1396 modest_mail_operation_update_account (ModestMailOperation *self,
1397 const gchar *account_name,
1398 UpdateAccountCallback callback,
1401 GThread *thread = NULL;
1402 UpdateAccountInfo *info = NULL;
1403 ModestMailOperationPrivate *priv = NULL;
1404 ModestAccountMgr *mgr = NULL;
1405 TnyStoreAccount *store_account = NULL;
1406 TnyTransportAccount *transport_account = NULL;
1408 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1409 g_return_val_if_fail (account_name, FALSE);
1411 /* Init mail operation. Set total and done to 0, and do not
1412 update them, this way the progress objects will know that
1413 we have no clue about the number of the objects */
1414 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1417 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1419 /* Get the Modest account */
1420 store_account = (TnyStoreAccount *)
1421 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1423 TNY_ACCOUNT_TYPE_STORE);
1425 /* Make sure that we have a connection, and request one
1427 * TODO: Is there some way to trigger this for every attempt to
1428 * use the network? */
1429 if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
1432 if (!store_account) {
1433 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1434 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1435 "cannot get tny store account for %s\n", account_name);
1440 /* Get the transport account, we can not do it in the thread
1441 due to some problems with dbus */
1442 transport_account = (TnyTransportAccount *)
1443 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1445 if (!transport_account) {
1446 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1447 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1448 "cannot get tny transport account for %s\n", account_name);
1452 /* Create the helper object */
1453 info = g_slice_new (UpdateAccountInfo);
1454 info->mail_op = self;
1455 info->account = store_account;
1456 info->transport_account = transport_account;
1457 info->callback = callback;
1458 info->user_data = user_data;
1460 /* Get the message size limit */
1461 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1462 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1463 if (info->max_size == 0)
1464 info->max_size = G_MAXINT;
1466 info->max_size = info->max_size * KB;
1468 /* Get per-account retrieval type */
1469 mgr = modest_runtime_get_account_mgr ();
1470 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1471 MODEST_ACCOUNT_RETRIEVE, FALSE);
1473 /* Get per-account message amount retrieval limit */
1474 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1475 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1476 if (info->retrieve_limit == 0)
1477 info->retrieve_limit = G_MAXINT;
1479 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1481 /* Set account busy */
1482 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1483 priv->account_name = g_strdup(account_name);
1485 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1490 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1492 callback (self, 0, user_data);
1493 modest_mail_operation_notify_end (self);
1497 /* ******************************************************************* */
1498 /* ************************** STORE ACTIONS ************************* */
1499 /* ******************************************************************* */
1503 modest_mail_operation_create_folder (ModestMailOperation *self,
1504 TnyFolderStore *parent,
1507 ModestMailOperationPrivate *priv;
1508 TnyFolder *new_folder = NULL;
1510 TnyList *list = tny_simple_list_new ();
1511 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1513 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1514 g_return_val_if_fail (name, NULL);
1516 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1518 /* Check for already existing folder */
1519 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1520 tny_folder_store_get_folders (parent, list, query, NULL);
1521 g_object_unref (G_OBJECT (query));
1523 if (tny_list_get_length (list) > 0) {
1524 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1525 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1526 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1527 _CS("ckdg_ib_folder_already_exists"));
1530 g_object_unref (G_OBJECT (list));
1533 if (TNY_IS_FOLDER (parent)) {
1534 /* Check folder rules */
1535 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1536 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1537 /* Set status failed and set an error */
1538 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1539 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1540 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1541 _("mail_in_ui_folder_create_error"));
1545 if (!strcmp (name, " ") || strchr (name, '/')) {
1546 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1547 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1548 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1549 _("mail_in_ui_folder_create_error"));
1553 /* Create the folder */
1554 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1555 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1557 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1560 /* Notify about operation end */
1561 modest_mail_operation_notify_end (self);
1567 modest_mail_operation_remove_folder (ModestMailOperation *self,
1569 gboolean remove_to_trash)
1571 TnyAccount *account;
1572 ModestMailOperationPrivate *priv;
1573 ModestTnyFolderRules rules;
1575 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1576 g_return_if_fail (TNY_IS_FOLDER (folder));
1578 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1580 /* Check folder rules */
1581 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1582 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1583 /* Set status failed and set an error */
1584 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1585 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1586 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1587 _("mail_in_ui_folder_delete_error"));
1591 /* Get the account */
1592 account = modest_tny_folder_get_account (folder);
1593 priv->account = g_object_ref(account);
1595 /* Delete folder or move to trash */
1596 if (remove_to_trash) {
1597 TnyFolder *trash_folder = NULL;
1598 trash_folder = modest_tny_account_get_special_folder (account,
1599 TNY_FOLDER_TYPE_TRASH);
1600 /* TODO: error_handling */
1602 modest_mail_operation_xfer_folder (self, folder,
1603 TNY_FOLDER_STORE (trash_folder),
1605 g_object_unref (trash_folder);
1608 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1610 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1611 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1614 g_object_unref (G_OBJECT (parent));
1616 g_object_unref (G_OBJECT (account));
1619 /* Notify about operation end */
1620 modest_mail_operation_notify_end (self);
1624 transfer_folder_status_cb (GObject *obj,
1628 ModestMailOperation *self;
1629 ModestMailOperationPrivate *priv;
1630 ModestMailOperationState *state;
1631 XFerMsgAsyncHelper *helper;
1633 g_return_if_fail (status != NULL);
1634 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1636 helper = (XFerMsgAsyncHelper *) user_data;
1637 g_return_if_fail (helper != NULL);
1639 self = helper->mail_op;
1640 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1642 priv->done = status->position;
1643 priv->total = status->of_total;
1645 state = modest_mail_operation_clone_state (self);
1646 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1647 gdk_threads_enter ();
1649 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1650 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1651 gdk_threads_leave ();
1653 g_slice_free (ModestMailOperationState, state);
1658 transfer_folder_cb (TnyFolder *folder,
1659 TnyFolderStore *into,
1661 TnyFolder *new_folder,
1665 XFerMsgAsyncHelper *helper;
1666 ModestMailOperation *self = NULL;
1667 ModestMailOperationPrivate *priv = NULL;
1669 helper = (XFerMsgAsyncHelper *) user_data;
1670 g_return_if_fail (helper != NULL);
1672 self = helper->mail_op;
1673 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1676 priv->error = g_error_copy (*err);
1678 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1679 } else if (cancelled) {
1680 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1681 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1682 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1683 _("Transference of %s was cancelled."),
1684 tny_folder_get_name (folder));
1687 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1690 /* Notify about operation end */
1691 modest_mail_operation_notify_end (self);
1693 /* If user defined callback function was defined, call it */
1694 if (helper->user_callback) {
1695 gdk_threads_enter ();
1696 helper->user_callback (priv->source, helper->user_data);
1697 gdk_threads_leave ();
1701 g_object_unref (helper->mail_op);
1702 g_slice_free (XFerMsgAsyncHelper, helper);
1707 * This function checks if the new name is a valid name for our local
1708 * folders account. The new name could not be the same than then name
1709 * of any of the mandatory local folders
1711 * We can not rely on tinymail because tinymail does not check the
1712 * name of the virtual folders that the account could have in the case
1713 * that we're doing a rename (because it directly calls Camel which
1714 * knows nothing about our virtual folders).
1716 * In the case of an actual copy/move (i.e. move/copy a folder between
1717 * accounts) tinymail uses the tny_folder_store_create_account which
1718 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1719 * checks the new name of the folder, so this call in that case
1720 * wouldn't be needed. *But* NOTE that if tinymail changes its
1721 * implementation (if folder transfers within the same account is no
1722 * longer implemented as a rename) this call will allow Modest to work
1725 * If the new name is not valid, this function will set the status to
1726 * failed and will set also an error in the mail operation
1729 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1730 TnyFolderStore *into,
1731 const gchar *new_name)
1733 if (TNY_IS_ACCOUNT (into) &&
1734 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1735 modest_tny_local_folders_account_extra_folder_exists (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1737 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1738 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1739 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1740 _("FIXME: folder name already in use"));
1747 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1749 TnyFolderStore *parent,
1750 gboolean delete_original,
1751 XferMsgsAsynUserCallback user_callback,
1754 ModestMailOperationPrivate *priv = NULL;
1755 ModestTnyFolderRules parent_rules = 0, rules;
1756 XFerMsgAsyncHelper *helper = NULL;
1758 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1759 g_return_if_fail (TNY_IS_FOLDER (folder));
1761 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1763 /* Get account and set it into mail_operation */
1764 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1765 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1767 /* Get folder rules */
1768 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1769 if (TNY_IS_FOLDER (parent))
1770 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1772 /* The moveable restriction is applied also to copy operation */
1773 if ((gpointer) parent == (gpointer) folder ||
1774 (!TNY_IS_FOLDER_STORE (parent)) ||
1775 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1776 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1777 /* Set status failed and set an error */
1778 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1779 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1780 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1781 _("mail_in_ui_folder_move_target_error"));
1783 /* Notify the queue */
1784 modest_mail_operation_notify_end (self);
1785 } else if (TNY_IS_FOLDER (parent) &&
1786 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1787 /* Set status failed and set an error */
1788 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1789 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1790 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1791 _("FIXME: parent folder does not accept new folders"));
1793 /* Notify the queue */
1794 modest_mail_operation_notify_end (self);
1798 /* Check that the new folder name is not used by any
1799 special local folder */
1800 if (new_name_valid_if_local_account (priv, parent,
1801 tny_folder_get_name (folder))) {
1802 /* Create the helper */
1803 helper = g_slice_new0 (XFerMsgAsyncHelper);
1804 helper->mail_op = g_object_ref(self);
1805 helper->dest_folder = NULL;
1806 helper->headers = NULL;
1807 helper->user_callback = user_callback;
1808 helper->user_data = user_data;
1810 /* Move/Copy folder */
1811 tny_folder_copy_async (folder,
1813 tny_folder_get_name (folder),
1816 transfer_folder_status_cb,
1819 modest_mail_operation_notify_end (self);
1825 modest_mail_operation_rename_folder (ModestMailOperation *self,
1829 ModestMailOperationPrivate *priv;
1830 ModestTnyFolderRules rules;
1831 XFerMsgAsyncHelper *helper;
1833 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1834 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1835 g_return_if_fail (name);
1837 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1839 /* Get account and set it into mail_operation */
1840 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1842 /* Check folder rules */
1843 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1844 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1845 /* Set status failed and set an error */
1846 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1847 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1848 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1849 _("FIXME: unable to rename"));
1851 /* Notify about operation end */
1852 modest_mail_operation_notify_end (self);
1853 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1854 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1855 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1856 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1857 _("FIXME: unable to rename"));
1858 /* Notify about operation end */
1859 modest_mail_operation_notify_end (self);
1861 TnyFolderStore *into;
1863 into = tny_folder_get_folder_store (folder);
1865 /* Check that the new folder name is not used by any
1866 special local folder */
1867 if (new_name_valid_if_local_account (priv, into, name)) {
1868 /* Create the helper */
1869 helper = g_slice_new0 (XFerMsgAsyncHelper);
1870 helper->mail_op = g_object_ref(self);
1871 helper->dest_folder = NULL;
1872 helper->headers = NULL;
1873 helper->user_callback = NULL;
1874 helper->user_data = NULL;
1876 /* Rename. Camel handles folder subscription/unsubscription */
1877 tny_folder_copy_async (folder, into, name, TRUE,
1879 transfer_folder_status_cb,
1882 modest_mail_operation_notify_end (self);
1884 g_object_unref (into);
1888 /* ******************************************************************* */
1889 /* ************************** MSG ACTIONS ************************* */
1890 /* ******************************************************************* */
1892 void modest_mail_operation_get_msg (ModestMailOperation *self,
1894 GetMsgAsyncUserCallback user_callback,
1897 GetMsgAsyncHelper *helper = NULL;
1899 ModestMailOperationPrivate *priv;
1901 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1902 g_return_if_fail (TNY_IS_HEADER (header));
1904 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1905 folder = tny_header_get_folder (header);
1907 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1909 /* Get message from folder */
1911 /* Get account and set it into mail_operation */
1912 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1914 helper = g_slice_new0 (GetMsgAsyncHelper);
1915 helper->mail_op = self;
1916 helper->user_callback = user_callback;
1917 helper->user_data = user_data;
1918 helper->header = g_object_ref (header);
1920 // The callback's reference so that the mail op is not
1921 // finalized until the async operation is completed even if
1922 // the user canceled the request meanwhile.
1923 g_object_ref (G_OBJECT (helper->mail_op));
1925 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1927 g_object_unref (G_OBJECT (folder));
1929 /* Set status failed and set an error */
1930 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1931 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1932 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1933 _("Error trying to get a message. No folder found for header"));
1935 /* Notify the queue */
1936 modest_mail_operation_notify_end (self);
1941 idle_get_mime_part_size_cb (gpointer userdata)
1943 GetMimePartSizeInfo *idle_info;
1945 idle_info = (GetMimePartSizeInfo *) userdata;
1947 gdk_threads_enter ();
1948 idle_info->callback (idle_info->mail_op,
1950 idle_info->userdata);
1951 gdk_threads_leave ();
1953 g_object_unref (idle_info->mail_op);
1954 g_slice_free (GetMimePartSizeInfo, idle_info);
1960 get_mime_part_size_thread (gpointer thr_user_data)
1962 GetMimePartSizeInfo *info;
1963 gchar read_buffer[GET_SIZE_BUFFER_SIZE];
1967 ModestMailOperationPrivate *priv;
1969 info = (GetMimePartSizeInfo *) thr_user_data;
1970 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1972 stream = tny_camel_mem_stream_new ();
1973 tny_mime_part_decode_to_stream (info->mime_part, stream);
1974 tny_stream_reset (stream);
1975 if (tny_stream_is_eos (stream)) {
1976 tny_stream_close (stream);
1977 stream = tny_mime_part_get_stream (info->mime_part);
1980 while (!tny_stream_is_eos (stream)) {
1981 readed_size = tny_stream_read (stream, read_buffer, GET_SIZE_BUFFER_SIZE);
1982 total += readed_size;
1985 if (info->callback) {
1986 GetMimePartSizeInfo *idle_info;
1988 idle_info = g_slice_new0 (GetMimePartSizeInfo);
1989 idle_info->mail_op = g_object_ref (info->mail_op);
1990 idle_info->size = total;
1991 idle_info->callback = info->callback;
1992 idle_info->userdata = info->userdata;
1993 g_idle_add (idle_get_mime_part_size_cb, idle_info);
1996 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1998 g_object_unref (info->mail_op);
1999 g_object_unref (stream);
2000 g_object_unref (info->mime_part);
2001 g_slice_free (GetMimePartSizeInfo, info);
2007 modest_mail_operation_get_mime_part_size (ModestMailOperation *self,
2009 GetMimePartSizeCallback user_callback,
2011 GDestroyNotify notify)
2013 GetMimePartSizeInfo *info;
2014 ModestMailOperationPrivate *priv;
2017 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2018 g_return_if_fail (TNY_IS_MIME_PART (part));
2020 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2022 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2023 info = g_slice_new0 (GetMimePartSizeInfo);
2024 info->mail_op = g_object_ref (self);
2025 info->mime_part = g_object_ref (part);
2026 info->callback = user_callback;
2027 info->userdata = user_data;
2029 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2034 get_msg_cb (TnyFolder *folder,
2040 GetMsgAsyncHelper *helper = NULL;
2041 ModestMailOperation *self = NULL;
2042 ModestMailOperationPrivate *priv = NULL;
2044 helper = (GetMsgAsyncHelper *) user_data;
2045 g_return_if_fail (helper != NULL);
2046 self = helper->mail_op;
2047 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2048 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2050 /* Check errors and cancel */
2052 priv->error = g_error_copy (*error);
2053 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2054 } else if (cancelled) {
2055 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2056 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2057 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2058 _("Error trying to refresh the contents of %s"),
2059 tny_folder_get_name (folder));
2061 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2064 /* If user defined callback function was defined, call it even
2065 if the operation failed*/
2066 if (helper->user_callback) {
2067 /* This callback is called into an iddle by tinymail,
2068 and idles are not in the main lock */
2069 gdk_threads_enter ();
2070 helper->user_callback (self, helper->header, msg, helper->user_data);
2071 gdk_threads_leave ();
2074 /* Notify about operation end */
2075 modest_mail_operation_notify_end (self);
2077 g_object_unref (helper->mail_op);
2078 g_object_unref (helper->header);
2079 g_slice_free (GetMsgAsyncHelper, helper);
2084 get_msg_status_cb (GObject *obj,
2088 GetMsgAsyncHelper *helper = NULL;
2089 ModestMailOperation *self;
2090 ModestMailOperationPrivate *priv;
2091 ModestMailOperationState *state;
2093 g_return_if_fail (status != NULL);
2094 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2096 helper = (GetMsgAsyncHelper *) user_data;
2097 g_return_if_fail (helper != NULL);
2099 self = helper->mail_op;
2100 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2105 state = modest_mail_operation_clone_state (self);
2106 state->bytes_done = status->position;
2107 state->bytes_total = status->of_total;
2108 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2109 gdk_threads_enter ();
2111 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2112 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2113 gdk_threads_leave ();
2115 g_slice_free (ModestMailOperationState, state);
2118 /****************************************************/
2120 ModestMailOperation *mail_op;
2122 GetMsgAsyncUserCallback user_callback;
2124 GDestroyNotify notify;
2128 GetMsgAsyncUserCallback user_callback;
2132 ModestMailOperation *mail_op;
2133 } NotifyGetMsgsInfo;
2137 * Used by get_msgs_full_thread to call the user_callback for each
2138 * message that has been read
2141 notify_get_msgs_full (gpointer data)
2143 NotifyGetMsgsInfo *info;
2145 info = (NotifyGetMsgsInfo *) data;
2147 /* Call the user callback. Idles are not in the main lock, so
2149 gdk_threads_enter ();
2150 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2151 gdk_threads_leave ();
2153 g_slice_free (NotifyGetMsgsInfo, info);
2159 * Used by get_msgs_full_thread to free al the thread resources and to
2160 * call the destroy function for the passed user_data
2163 get_msgs_full_destroyer (gpointer data)
2165 GetFullMsgsInfo *info;
2167 info = (GetFullMsgsInfo *) data;
2170 gdk_threads_enter ();
2171 info->notify (info->user_data);
2172 gdk_threads_leave ();
2176 g_object_unref (info->headers);
2177 g_slice_free (GetFullMsgsInfo, info);
2183 get_msgs_full_thread (gpointer thr_user_data)
2185 GetFullMsgsInfo *info;
2186 ModestMailOperationPrivate *priv = NULL;
2187 TnyIterator *iter = NULL;
2189 info = (GetFullMsgsInfo *) thr_user_data;
2190 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2192 iter = tny_list_create_iterator (info->headers);
2193 while (!tny_iterator_is_done (iter)) {
2197 header = TNY_HEADER (tny_iterator_get_current (iter));
2198 folder = tny_header_get_folder (header);
2200 /* Get message from folder */
2203 /* The callback will call it per each header */
2204 msg = tny_folder_get_msg (folder, header, &(priv->error));
2207 ModestMailOperationState *state;
2212 /* notify progress */
2213 state = modest_mail_operation_clone_state (info->mail_op);
2214 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2215 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2216 pair, (GDestroyNotify) modest_pair_free);
2218 /* The callback is the responsible for
2219 freeing the message */
2220 if (info->user_callback) {
2221 NotifyGetMsgsInfo *info_notify;
2222 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2223 info_notify->user_callback = info->user_callback;
2224 info_notify->mail_op = info->mail_op;
2225 info_notify->header = g_object_ref (header);
2226 info_notify->msg = g_object_ref (msg);
2227 info_notify->user_data = info->user_data;
2228 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2229 notify_get_msgs_full,
2232 g_object_unref (msg);
2235 /* Set status failed and set an error */
2236 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2237 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2238 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2239 "Error trying to get a message. No folder found for header");
2243 g_object_unref (header);
2245 tny_iterator_next (iter);
2248 /* Set operation status */
2249 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2250 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2252 /* Notify about operation end */
2253 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2255 /* Free thread resources. Will be called after all previous idles */
2256 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2262 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2263 TnyList *header_list,
2264 GetMsgAsyncUserCallback user_callback,
2266 GDestroyNotify notify)
2268 TnyHeader *header = NULL;
2269 TnyFolder *folder = NULL;
2271 ModestMailOperationPrivate *priv = NULL;
2272 GetFullMsgsInfo *info = NULL;
2273 gboolean size_ok = TRUE;
2275 TnyIterator *iter = NULL;
2277 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2279 /* Init mail operation */
2280 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2281 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2283 priv->total = tny_list_get_length(header_list);
2285 /* Get account and set it into mail_operation */
2286 if (tny_list_get_length (header_list) >= 1) {
2287 iter = tny_list_create_iterator (header_list);
2288 header = TNY_HEADER (tny_iterator_get_current (iter));
2290 folder = tny_header_get_folder (header);
2292 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2294 g_object_unref (folder);
2297 g_object_unref (header);
2300 if (tny_list_get_length (header_list) == 1) {
2301 g_object_unref (iter);
2306 /* Get msg size limit */
2307 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2308 MODEST_CONF_MSG_SIZE_LIMIT,
2311 g_clear_error (&(priv->error));
2312 max_size = G_MAXINT;
2314 max_size = max_size * KB;
2317 /* Check message size limits. If there is only one message
2318 always retrieve it */
2320 while (!tny_iterator_is_done (iter) && size_ok) {
2321 header = TNY_HEADER (tny_iterator_get_current (iter));
2323 if (tny_header_get_message_size (header) >= max_size)
2325 g_object_unref (header);
2328 tny_iterator_next (iter);
2330 g_object_unref (iter);
2334 /* Create the info */
2335 info = g_slice_new0 (GetFullMsgsInfo);
2336 info->mail_op = self;
2337 info->user_callback = user_callback;
2338 info->user_data = user_data;
2339 info->headers = g_object_ref (header_list);
2340 info->notify = notify;
2342 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2344 /* Set status failed and set an error */
2345 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2346 /* FIXME: the error msg is different for pop */
2347 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2348 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2349 _("emev_ni_ui_imap_msg_size_exceed_error"));
2350 /* Remove from queue and free resources */
2351 modest_mail_operation_notify_end (self);
2359 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2360 gboolean remove_to_trash /*ignored*/)
2363 ModestMailOperationPrivate *priv;
2365 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2366 g_return_if_fail (TNY_IS_HEADER (header));
2368 if (remove_to_trash)
2369 g_warning ("remove to trash is not implemented");
2371 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2372 folder = tny_header_get_folder (header);
2374 /* Get account and set it into mail_operation */
2375 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2377 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2380 tny_folder_remove_msg (folder, header, &(priv->error));
2382 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2383 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2385 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2386 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2387 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2388 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2391 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2397 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2399 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2402 g_object_unref (G_OBJECT (folder));
2404 /* Notify about operation end */
2405 modest_mail_operation_notify_end (self);
2409 transfer_msgs_status_cb (GObject *obj,
2413 XFerMsgAsyncHelper *helper = NULL;
2414 ModestMailOperation *self;
2415 ModestMailOperationPrivate *priv;
2416 ModestMailOperationState *state;
2419 g_return_if_fail (status != NULL);
2420 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2422 helper = (XFerMsgAsyncHelper *) user_data;
2423 g_return_if_fail (helper != NULL);
2425 self = helper->mail_op;
2426 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2428 priv->done = status->position;
2429 priv->total = status->of_total;
2431 state = modest_mail_operation_clone_state (self);
2432 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2433 gdk_threads_enter ();
2435 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2436 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2437 gdk_threads_leave ();
2439 g_slice_free (ModestMailOperationState, state);
2444 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2446 XFerMsgAsyncHelper *helper;
2447 ModestMailOperation *self;
2448 ModestMailOperationPrivate *priv;
2450 helper = (XFerMsgAsyncHelper *) user_data;
2451 self = helper->mail_op;
2453 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2456 priv->error = g_error_copy (*err);
2458 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2459 } else if (cancelled) {
2460 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2461 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2462 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2463 _("Error trying to refresh the contents of %s"),
2464 tny_folder_get_name (folder));
2467 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2470 /* Notify about operation end */
2471 modest_mail_operation_notify_end (self);
2473 /* If user defined callback function was defined, call it */
2474 if (helper->user_callback) {
2475 gdk_threads_enter ();
2476 helper->user_callback (priv->source, helper->user_data);
2477 gdk_threads_leave ();
2481 g_object_unref (helper->headers);
2482 g_object_unref (helper->dest_folder);
2483 g_object_unref (helper->mail_op);
2484 g_slice_free (XFerMsgAsyncHelper, helper);
2485 g_object_unref (folder);
2490 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2493 gboolean delete_original,
2494 XferMsgsAsynUserCallback user_callback,
2497 ModestMailOperationPrivate *priv = NULL;
2498 TnyIterator *iter = NULL;
2499 TnyFolder *src_folder = NULL;
2500 XFerMsgAsyncHelper *helper = NULL;
2501 TnyHeader *header = NULL;
2502 ModestTnyFolderRules rules = 0;
2503 const gchar *id1 = NULL;
2504 const gchar *id2 = NULL;
2505 gboolean same_folder = FALSE;
2507 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2508 g_return_if_fail (TNY_IS_LIST (headers));
2509 g_return_if_fail (TNY_IS_FOLDER (folder));
2511 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2514 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2516 /* Apply folder rules */
2517 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2518 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2519 /* Set status failed and set an error */
2520 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2521 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2522 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2523 _CS("ckct_ib_unable_to_paste_here"));
2524 /* Notify the queue */
2525 modest_mail_operation_notify_end (self);
2529 /* Get source folder */
2530 iter = tny_list_create_iterator (headers);
2531 header = TNY_HEADER (tny_iterator_get_current (iter));
2533 src_folder = tny_header_get_folder (header);
2534 g_object_unref (header);
2537 g_object_unref (iter);
2539 /* Check folder source and destination */
2540 id1 = tny_folder_get_id (src_folder);
2541 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2542 same_folder = !g_ascii_strcasecmp (id1, id2);
2544 /* Set status failed and set an error */
2545 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2546 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2547 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2548 _("mcen_ib_unable_to_copy_samefolder"));
2550 /* Notify the queue */
2551 modest_mail_operation_notify_end (self);
2554 g_object_unref (src_folder);
2558 /* Create the helper */
2559 helper = g_slice_new0 (XFerMsgAsyncHelper);
2560 helper->mail_op = g_object_ref(self);
2561 helper->dest_folder = g_object_ref(folder);
2562 helper->headers = g_object_ref(headers);
2563 helper->user_callback = user_callback;
2564 helper->user_data = user_data;
2566 /* Get account and set it into mail_operation */
2567 priv->account = modest_tny_folder_get_account (src_folder);
2569 /* Transfer messages */
2570 tny_folder_transfer_msgs_async (src_folder,
2575 transfer_msgs_status_cb,
2581 on_refresh_folder (TnyFolder *folder,
2586 RefreshAsyncHelper *helper = NULL;
2587 ModestMailOperation *self = NULL;
2588 ModestMailOperationPrivate *priv = NULL;
2590 helper = (RefreshAsyncHelper *) user_data;
2591 self = helper->mail_op;
2592 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2595 priv->error = g_error_copy (*error);
2596 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2601 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2602 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2603 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2604 _("Error trying to refresh the contents of %s"),
2605 tny_folder_get_name (folder));
2609 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2611 /* Call user defined callback, if it exists */
2612 if (helper->user_callback) {
2613 gdk_threads_enter ();
2614 helper->user_callback (self, folder, helper->user_data);
2615 gdk_threads_leave ();
2619 /* g_object_unref (helper->mail_op); */
2620 g_slice_free (RefreshAsyncHelper, helper);
2622 /* Notify about operation end */
2623 modest_mail_operation_notify_end (self);
2627 on_refresh_folder_status_update (GObject *obj,
2631 RefreshAsyncHelper *helper = NULL;
2632 ModestMailOperation *self = NULL;
2633 ModestMailOperationPrivate *priv = NULL;
2634 ModestMailOperationState *state;
2636 g_return_if_fail (user_data != NULL);
2637 g_return_if_fail (status != NULL);
2638 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2640 helper = (RefreshAsyncHelper *) user_data;
2641 self = helper->mail_op;
2642 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2644 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2646 priv->done = status->position;
2647 priv->total = status->of_total;
2649 state = modest_mail_operation_clone_state (self);
2650 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2651 gdk_threads_enter ();
2653 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2654 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2655 gdk_threads_leave ();
2657 g_slice_free (ModestMailOperationState, state);
2661 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2663 RefreshAsyncUserCallback user_callback,
2666 ModestMailOperationPrivate *priv = NULL;
2667 RefreshAsyncHelper *helper = NULL;
2669 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2671 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2673 /* Get account and set it into mail_operation */
2674 priv->account = modest_tny_folder_get_account (folder);
2676 /* Create the helper */
2677 helper = g_slice_new0 (RefreshAsyncHelper);
2678 helper->mail_op = g_object_ref (self);
2679 helper->user_callback = user_callback;
2680 helper->user_data = user_data;
2682 /* Refresh the folder. TODO: tinymail could issue a status
2683 updates before the callback call then this could happen. We
2684 must review the design */
2685 tny_folder_refresh_async (folder,
2687 on_refresh_folder_status_update,
2693 * It's used by the mail operation queue to notify the observers
2694 * attached to that signal that the operation finished. We need to use
2695 * that because tinymail does not give us the progress of a given
2696 * operation when it finishes (it directly calls the operation
2700 modest_mail_operation_notify_end (ModestMailOperation *self)
2702 ModestMailOperationState *state;
2703 ModestMailOperationPrivate *priv = NULL;
2705 g_return_if_fail (self);
2707 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2709 /* Set the account back to not busy */
2710 if (priv->account_name) {
2711 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2712 priv->account_name, FALSE);
2713 g_free(priv->account_name);
2714 priv->account_name = NULL;
2717 /* Notify the observers about the mail operation end */
2718 /* We do not wrapp this emission because we assume that this
2719 function is always called from within the main lock */
2720 state = modest_mail_operation_clone_state (self);
2721 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2722 g_slice_free (ModestMailOperationState, state);