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-account-mgr-helpers.h"
49 #include <modest-tny-account.h>
50 #include <modest-tny-send-queue.h>
51 #include <modest-runtime.h>
52 #include "modest-text-utils.h"
53 #include "modest-tny-msg.h"
54 #include "modest-tny-folder.h"
55 #include "modest-tny-account-store.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-marshal.h"
58 #include "modest-error.h"
59 #include "modest-mail-operation.h"
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 XferAsyncUserCallback user_callback;
136 } XFerMsgAsyncHelper;
138 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
142 static void modest_mail_operation_create_msg (ModestMailOperation *self,
143 const gchar *from, const gchar *to,
144 const gchar *cc, const gchar *bcc,
145 const gchar *subject, const gchar *plain_body,
146 const gchar *html_body, const GList *attachments_list,
147 TnyHeaderFlags priority_flags,
148 ModestMailOperationCreateMsgCallback callback,
151 static gboolean idle_notify_queue (gpointer data);
154 ModestMailOperation *mail_op;
162 GList *attachments_list;
163 TnyHeaderFlags priority_flags;
164 ModestMailOperationCreateMsgCallback callback;
170 ModestMailOperation *mail_op;
172 ModestMailOperationCreateMsgCallback callback;
177 static GObjectClass *parent_class = NULL;
179 static guint signals[NUM_SIGNALS] = {0};
182 modest_mail_operation_get_type (void)
184 static GType my_type = 0;
186 static const GTypeInfo my_info = {
187 sizeof(ModestMailOperationClass),
188 NULL, /* base init */
189 NULL, /* base finalize */
190 (GClassInitFunc) modest_mail_operation_class_init,
191 NULL, /* class finalize */
192 NULL, /* class data */
193 sizeof(ModestMailOperation),
195 (GInstanceInitFunc) modest_mail_operation_init,
198 my_type = g_type_register_static (G_TYPE_OBJECT,
199 "ModestMailOperation",
206 modest_mail_operation_class_init (ModestMailOperationClass *klass)
208 GObjectClass *gobject_class;
209 gobject_class = (GObjectClass*) klass;
211 parent_class = g_type_class_peek_parent (klass);
212 gobject_class->finalize = modest_mail_operation_finalize;
214 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
217 * ModestMailOperation::progress-changed
218 * @self: the #MailOperation that emits the signal
219 * @user_data: user data set when the signal handler was connected
221 * Emitted when the progress of a mail operation changes
223 signals[PROGRESS_CHANGED_SIGNAL] =
224 g_signal_new ("progress-changed",
225 G_TYPE_FROM_CLASS (gobject_class),
227 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
229 g_cclosure_marshal_VOID__POINTER,
230 G_TYPE_NONE, 1, G_TYPE_POINTER);
235 modest_mail_operation_init (ModestMailOperation *obj)
237 ModestMailOperationPrivate *priv;
239 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
241 priv->account = NULL;
242 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
243 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
248 priv->error_checking = NULL;
249 priv->error_checking_user_data = NULL;
253 modest_mail_operation_finalize (GObject *obj)
255 ModestMailOperationPrivate *priv;
257 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
262 g_error_free (priv->error);
266 g_object_unref (priv->source);
270 g_object_unref (priv->account);
271 priv->account = NULL;
275 G_OBJECT_CLASS(parent_class)->finalize (obj);
279 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
282 ModestMailOperation *obj;
283 ModestMailOperationPrivate *priv;
285 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
286 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
288 priv->op_type = op_type;
290 priv->source = g_object_ref(source);
296 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
298 ErrorCheckingUserCallback error_handler,
301 ModestMailOperation *obj;
302 ModestMailOperationPrivate *priv;
304 obj = modest_mail_operation_new (op_type, source);
305 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
307 g_return_val_if_fail (error_handler != NULL, obj);
308 priv->error_checking = error_handler;
309 priv->error_checking_user_data = user_data;
315 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
317 ModestMailOperationPrivate *priv;
319 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
320 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
322 if (priv->error_checking != NULL)
323 priv->error_checking (self, priv->error_checking_user_data);
327 ModestMailOperationTypeOperation
328 modest_mail_operation_get_type_operation (ModestMailOperation *self)
330 ModestMailOperationPrivate *priv;
332 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
334 return priv->op_type;
338 modest_mail_operation_is_mine (ModestMailOperation *self,
341 ModestMailOperationPrivate *priv;
343 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
344 if (priv->source == NULL) return FALSE;
346 return priv->source == me;
350 modest_mail_operation_get_source (ModestMailOperation *self)
352 ModestMailOperationPrivate *priv;
354 g_return_val_if_fail (self, NULL);
356 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
358 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
362 return (priv->source) ? g_object_ref (priv->source) : NULL;
365 ModestMailOperationStatus
366 modest_mail_operation_get_status (ModestMailOperation *self)
368 ModestMailOperationPrivate *priv;
370 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
371 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
372 MODEST_MAIL_OPERATION_STATUS_INVALID);
374 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
376 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
377 return MODEST_MAIL_OPERATION_STATUS_INVALID;
384 modest_mail_operation_get_error (ModestMailOperation *self)
386 ModestMailOperationPrivate *priv;
388 g_return_val_if_fail (self, NULL);
389 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
391 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
394 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
402 modest_mail_operation_cancel (ModestMailOperation *self)
404 ModestMailOperationPrivate *priv;
405 gboolean canceled = FALSE;
407 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
409 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
411 /* Note that if we call cancel with an already canceled mail
412 operation the progress changed signal won't be emitted */
413 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
417 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
419 /* Cancel the mail operation. We need to wrap it between this
420 start/stop operations to allow following calls to the
422 g_return_val_if_fail (priv->account, FALSE);
423 tny_account_cancel (priv->account);
429 modest_mail_operation_get_task_done (ModestMailOperation *self)
431 ModestMailOperationPrivate *priv;
433 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
435 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
440 modest_mail_operation_get_task_total (ModestMailOperation *self)
442 ModestMailOperationPrivate *priv;
444 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
446 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
451 modest_mail_operation_is_finished (ModestMailOperation *self)
453 ModestMailOperationPrivate *priv;
454 gboolean retval = FALSE;
456 if (!MODEST_IS_MAIL_OPERATION (self)) {
457 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
461 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
463 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
464 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
465 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
466 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
476 modest_mail_operation_get_id (ModestMailOperation *self)
478 ModestMailOperationPrivate *priv;
480 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
482 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
487 modest_mail_operation_set_id (ModestMailOperation *self,
490 ModestMailOperationPrivate *priv;
492 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
494 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
499 * Creates an image of the current state of a mail operation, the
500 * caller must free it
502 static ModestMailOperationState *
503 modest_mail_operation_clone_state (ModestMailOperation *self)
505 ModestMailOperationState *state;
506 ModestMailOperationPrivate *priv;
508 /* FIXME: this should be fixed properly
510 * in some cases, priv was NULL, so checking here to
513 g_return_val_if_fail (self, NULL);
514 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
515 g_return_val_if_fail (priv, NULL);
520 state = g_slice_new (ModestMailOperationState);
522 state->status = priv->status;
523 state->op_type = priv->op_type;
524 state->done = priv->done;
525 state->total = priv->total;
526 state->finished = modest_mail_operation_is_finished (self);
527 state->bytes_done = 0;
528 state->bytes_total = 0;
533 /* ******************************************************************* */
534 /* ************************** SEND ACTIONS ************************* */
535 /* ******************************************************************* */
538 modest_mail_operation_send_mail (ModestMailOperation *self,
539 TnyTransportAccount *transport_account,
542 TnySendQueue *send_queue = NULL;
543 ModestMailOperationPrivate *priv;
545 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
546 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
547 g_return_if_fail (TNY_IS_MSG (msg));
549 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
551 /* Get account and set it into mail_operation */
552 priv->account = g_object_ref (transport_account);
556 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
557 if (!TNY_IS_SEND_QUEUE(send_queue)) {
558 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
559 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
560 "modest: could not find send queue for account\n");
561 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
564 /* TODO: connect to the msg-sent in order to know when
565 the mail operation is finished */
567 /* tny_send_queue_add (send_queue, msg, &(priv->error)); */
568 modest_tny_send_queue_add (MODEST_TNY_SEND_QUEUE(send_queue),
572 /* TODO: we're setting always success, do the check in
574 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
577 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)
578 modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
580 /* TODO: do this in the handler of the "msg-sent"
581 signal.Notify about operation end */
582 modest_mail_operation_notify_end (self);
586 idle_create_msg_cb (gpointer idle_data)
588 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
590 /* This is a GDK lock because we are an idle callback and
591 * info->callback can contain Gtk+ code */
593 gdk_threads_enter (); /* CHECKED */
594 info->callback (info->mail_op, info->msg, info->userdata);
596 g_object_unref (info->mail_op);
598 g_object_unref (info->msg);
599 g_slice_free (CreateMsgIdleInfo, info);
600 gdk_threads_leave (); /* CHECKED */
606 create_msg_thread (gpointer thread_data)
608 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
609 TnyMsg *new_msg = NULL;
610 ModestMailOperationPrivate *priv;
612 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
613 if (info->html_body == NULL) {
614 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
615 info->bcc, info->subject, info->plain_body,
616 info->attachments_list); /* FIXME: attachments */
618 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
619 info->bcc, info->subject, info->html_body,
620 info->plain_body, info->attachments_list);
625 TnyHeaderFlags flags = 0;
627 /* Set priority flags in message */
628 header = tny_msg_get_header (new_msg);
629 if (info->priority_flags != 0)
630 flags |= info->priority_flags;
632 /* Set attachment flags in message */
633 if (info->attachments_list != NULL)
634 flags |= TNY_HEADER_FLAG_ATTACHMENTS;
636 tny_header_set_flags (header, flags);
637 g_object_unref (G_OBJECT(header));
639 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
640 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
641 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
642 "modest: failed to create a new msg\n");
650 g_free (info->plain_body);
651 g_free (info->html_body);
652 g_free (info->subject);
653 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
654 g_list_free (info->attachments_list);
656 if (info->callback) {
657 CreateMsgIdleInfo *idle_info;
658 idle_info = g_slice_new0 (CreateMsgIdleInfo);
659 idle_info->mail_op = info->mail_op;
660 g_object_ref (info->mail_op);
661 idle_info->msg = new_msg;
663 g_object_ref (new_msg);
664 idle_info->callback = info->callback;
665 idle_info->userdata = info->userdata;
666 g_idle_add (idle_create_msg_cb, idle_info);
668 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
671 g_object_unref (info->mail_op);
672 g_slice_free (CreateMsgInfo, info);
677 modest_mail_operation_create_msg (ModestMailOperation *self,
678 const gchar *from, const gchar *to,
679 const gchar *cc, const gchar *bcc,
680 const gchar *subject, const gchar *plain_body,
681 const gchar *html_body,
682 const GList *attachments_list,
683 TnyHeaderFlags priority_flags,
684 ModestMailOperationCreateMsgCallback callback,
687 CreateMsgInfo *info = NULL;
689 info = g_slice_new0 (CreateMsgInfo);
690 info->mail_op = self;
693 info->from = g_strdup (from);
694 info->to = g_strdup (to);
695 info->cc = g_strdup (cc);
696 info->bcc = g_strdup (bcc);
697 info->subject = g_strdup (subject);
698 info->plain_body = g_strdup (plain_body);
699 info->html_body = g_strdup (html_body);
700 info->attachments_list = g_list_copy ((GList *) attachments_list);
701 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
702 info->priority_flags = priority_flags;
704 info->callback = callback;
705 info->userdata = userdata;
707 g_thread_create (create_msg_thread, info, FALSE, NULL);
712 TnyTransportAccount *transport_account;
717 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
721 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
722 TnyFolder *draft_folder = NULL;
723 TnyFolder *outbox_folder = NULL;
731 /* Call mail operation */
732 modest_mail_operation_send_mail (self, info->transport_account, msg);
734 /* Remove old mail from its source folder */
735 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
736 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_OUTBOX);
737 if (info->draft_msg != NULL) {
738 TnyFolder *folder = NULL;
739 TnyFolder *src_folder = NULL;
740 TnyFolderType folder_type;
741 folder = tny_msg_get_folder (info->draft_msg);
742 if (folder == NULL) goto end;
743 folder_type = modest_tny_folder_guess_folder_type (folder);
744 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
745 src_folder = outbox_folder;
747 src_folder = draft_folder;
749 /* Note: This can fail (with a warning) if the message is not really already in a folder,
750 * because this function requires it to have a UID. */
751 header = tny_msg_get_header (info->draft_msg);
752 tny_folder_remove_msg (src_folder, header, NULL);
754 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
755 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
757 g_object_unref (header);
758 g_object_unref (folder);
765 g_object_unref (info->draft_msg);
767 g_object_unref (draft_folder);
769 g_object_unref (outbox_folder);
770 if (info->transport_account)
771 g_object_unref (info->transport_account);
772 g_slice_free (SendNewMailInfo, info);
773 modest_mail_operation_notify_end (self);
777 modest_mail_operation_send_new_mail (ModestMailOperation *self,
778 TnyTransportAccount *transport_account,
780 const gchar *from, const gchar *to,
781 const gchar *cc, const gchar *bcc,
782 const gchar *subject, const gchar *plain_body,
783 const gchar *html_body,
784 const GList *attachments_list,
785 TnyHeaderFlags priority_flags)
787 ModestMailOperationPrivate *priv = NULL;
788 SendNewMailInfo *info;
790 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
791 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
793 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
795 /* Check parametters */
797 /* Set status failed and set an error */
798 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
799 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
800 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
801 _("Error trying to send a mail. You need to set at least one recipient"));
804 info = g_slice_new0 (SendNewMailInfo);
805 info->transport_account = transport_account;
806 if (transport_account)
807 g_object_ref (transport_account);
808 info->draft_msg = draft_msg;
810 g_object_ref (draft_msg);
811 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
812 attachments_list, priority_flags,
813 modest_mail_operation_send_new_mail_cb, info);
819 TnyTransportAccount *transport_account;
821 ModestMsgEditWindow *edit_window;
825 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
829 TnyFolder *src_folder = NULL;
830 TnyFolder *drafts = NULL;
831 TnyHeader *header = NULL;
832 ModestMailOperationPrivate *priv = NULL;
833 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
835 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
837 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
838 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
839 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
840 "modest: failed to create a new msg\n");
844 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
845 TNY_FOLDER_TYPE_DRAFTS);
847 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
848 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
849 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
850 "modest: failed to create a new msg\n");
855 tny_folder_add_msg (drafts, msg, &(priv->error));
857 if ((!priv->error) && (info->draft_msg != NULL)) {
858 header = tny_msg_get_header (info->draft_msg);
859 src_folder = tny_header_get_folder (header);
861 /* Remove the old draft */
862 tny_folder_remove_msg (src_folder, header, NULL);
864 /* Synchronize to expunge and to update the msg counts */
865 tny_folder_sync_async (drafts, TRUE, NULL, NULL, NULL);
866 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
868 g_object_unref (header);
872 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
874 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
876 if (info->edit_window)
877 modest_msg_edit_window_set_draft (info->edit_window, msg);
882 g_object_unref (G_OBJECT(drafts));
884 g_object_unref (G_OBJECT(src_folder));
885 if (info->edit_window)
886 g_object_unref (G_OBJECT(info->edit_window));
888 g_object_unref (G_OBJECT (info->draft_msg));
889 if (info->transport_account)
890 g_object_unref (G_OBJECT(info->transport_account));
891 g_slice_free (SaveToDraftsInfo, info);
893 modest_mail_operation_notify_end (self);
897 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
898 TnyTransportAccount *transport_account,
900 ModestMsgEditWindow *edit_window,
901 const gchar *from, const gchar *to,
902 const gchar *cc, const gchar *bcc,
903 const gchar *subject, const gchar *plain_body,
904 const gchar *html_body,
905 const GList *attachments_list,
906 TnyHeaderFlags priority_flags)
908 ModestMailOperationPrivate *priv = NULL;
909 SaveToDraftsInfo *info = NULL;
911 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
912 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
914 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
916 /* Get account and set it into mail_operation */
917 priv->account = g_object_ref (transport_account);
919 info = g_slice_new0 (SaveToDraftsInfo);
920 info->transport_account = g_object_ref (transport_account);
921 info->draft_msg = draft_msg;
923 g_object_ref (draft_msg);
924 info->edit_window = edit_window;
926 g_object_ref (edit_window);
928 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
929 attachments_list, priority_flags,
930 modest_mail_operation_save_to_drafts_cb, info);
936 ModestMailOperation *mail_op;
937 TnyStoreAccount *account;
938 TnyTransportAccount *transport_account;
941 gchar *retrieve_type;
943 UpdateAccountCallback callback;
945 TnyList *new_headers;
950 ModestMailOperation *mail_op;
951 TnyMimePart *mime_part;
953 GetMimePartSizeCallback callback;
955 } GetMimePartSizeInfo;
957 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
958 /* We use this folder observer to track the headers that have been
959 * added to a folder */
962 TnyList *new_headers;
963 } InternalFolderObserver;
967 } InternalFolderObserverClass;
969 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
971 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
972 internal_folder_observer,
974 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
978 foreach_add_item (gpointer header, gpointer user_data)
980 tny_list_prepend (TNY_LIST (user_data),
981 g_object_ref (G_OBJECT (header)));
984 /* This is the method that looks for new messages in a folder */
986 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
988 InternalFolderObserver *derived = (InternalFolderObserver *)self;
990 TnyFolderChangeChanged changed;
992 changed = tny_folder_change_get_changed (change);
994 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
997 /* Get added headers */
998 list = tny_simple_list_new ();
999 tny_folder_change_get_added_headers (change, list);
1001 /* Add them to the folder observer */
1002 tny_list_foreach (list, foreach_add_item,
1003 derived->new_headers);
1005 g_object_unref (G_OBJECT (list));
1010 internal_folder_observer_init (InternalFolderObserver *self)
1012 self->new_headers = tny_simple_list_new ();
1015 internal_folder_observer_finalize (GObject *object)
1017 InternalFolderObserver *self;
1019 self = (InternalFolderObserver *) object;
1020 g_object_unref (self->new_headers);
1022 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1025 tny_folder_observer_init (TnyFolderObserverIface *iface)
1027 iface->update_func = internal_folder_observer_update;
1030 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1032 GObjectClass *object_class;
1034 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1035 object_class = (GObjectClass*) klass;
1036 object_class->finalize = internal_folder_observer_finalize;
1042 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
1045 TnyList *folders = tny_simple_list_new ();
1047 tny_folder_store_get_folders (store, folders, query, NULL);
1048 iter = tny_list_create_iterator (folders);
1050 while (!tny_iterator_is_done (iter)) {
1052 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1054 tny_list_prepend (all_folders, G_OBJECT (folder));
1055 recurse_folders (folder, query, all_folders);
1056 g_object_unref (G_OBJECT (folder));
1059 tny_iterator_next (iter);
1061 g_object_unref (G_OBJECT (iter));
1062 g_object_unref (G_OBJECT (folders));
1066 * Issues the "progress-changed" signal. The timer won't be removed,
1067 * so you must call g_source_remove to stop the signal emission
1070 idle_notify_progress (gpointer data)
1072 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1073 ModestMailOperationState *state;
1075 state = modest_mail_operation_clone_state (mail_op);
1077 /* This is a GDK lock because we are an idle callback and
1078 * the handlers of this signal can contain Gtk+ code */
1080 gdk_threads_enter (); /* CHECKED */
1081 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1082 gdk_threads_leave (); /* CHECKED */
1084 g_slice_free (ModestMailOperationState, state);
1090 * Issues the "progress-changed" signal and removes the timer. It uses
1091 * a lock to ensure that the progress information of the mail
1092 * operation is not modified while there are notifications pending
1095 idle_notify_progress_once (gpointer data)
1099 pair = (ModestPair *) data;
1101 /* This is a GDK lock because we are an idle callback and
1102 * the handlers of this signal can contain Gtk+ code */
1104 gdk_threads_enter (); /* CHECKED */
1105 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1106 gdk_threads_leave (); /* CHECKED */
1108 /* Free the state and the reference to the mail operation */
1109 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1110 g_object_unref (pair->first);
1116 * Used to notify the queue from the main
1117 * loop. We call it inside an idle call to achieve that
1120 idle_notify_queue (gpointer data)
1122 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1124 /* Do not need to block, the notify end will do it for us */
1125 modest_mail_operation_notify_end (mail_op);
1126 g_object_unref (mail_op);
1132 compare_headers_by_date (gconstpointer a,
1135 TnyHeader **header1, **header2;
1136 time_t sent1, sent2;
1138 header1 = (TnyHeader **) a;
1139 header2 = (TnyHeader **) b;
1141 sent1 = tny_header_get_date_sent (*header1);
1142 sent2 = tny_header_get_date_sent (*header2);
1144 /* We want the most recent ones (greater time_t) at the
1153 set_last_updated_idle (gpointer data)
1156 /* This is a GDK lock because we are an idle callback and
1157 * modest_account_mgr_set_last_updated can issue Gtk+ code */
1159 gdk_threads_enter (); /* CHECKED - please recheck */
1161 /* It does not matter if the time is not exactly the same than
1162 the time when this idle was called, it's just an
1163 approximation and it won't be very different */
1165 modest_account_mgr_set_last_updated (modest_runtime_get_account_mgr (),
1169 gdk_threads_leave (); /* CHECKED - please recheck */
1175 idle_update_account_cb (gpointer data)
1177 UpdateAccountInfo *idle_info;
1179 idle_info = (UpdateAccountInfo *) data;
1181 /* This is a GDK lock because we are an idle callback and
1182 * idle_info->callback can contain Gtk+ code */
1184 gdk_threads_enter (); /* CHECKED */
1185 idle_info->callback (idle_info->mail_op,
1186 idle_info->new_headers,
1187 idle_info->user_data);
1188 gdk_threads_leave (); /* CHECKED */
1191 g_object_unref (idle_info->mail_op);
1192 if (idle_info->new_headers)
1193 g_object_unref (idle_info->new_headers);
1200 get_all_folders_from_account (TnyStoreAccount *account,
1203 TnyList *all_folders = NULL;
1204 TnyIterator *iter = NULL;
1205 TnyFolderStoreQuery *query = NULL;
1207 all_folders = tny_simple_list_new ();
1208 query = tny_folder_store_query_new ();
1209 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1210 tny_folder_store_get_folders (TNY_FOLDER_STORE (account),
1217 g_object_unref (all_folders);
1221 iter = tny_list_create_iterator (all_folders);
1222 while (!tny_iterator_is_done (iter)) {
1223 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1225 recurse_folders (folder, query, all_folders);
1226 g_object_unref (folder);
1228 tny_iterator_next (iter);
1230 g_object_unref (G_OBJECT (iter));
1237 update_account_thread (gpointer thr_user_data)
1239 static gboolean first_time = TRUE;
1240 UpdateAccountInfo *info = NULL;
1241 TnyList *all_folders = NULL, *new_headers = NULL;
1242 GPtrArray *new_headers_array = NULL;
1243 TnyIterator *iter = NULL;
1244 ModestMailOperationPrivate *priv = NULL;
1245 ModestTnySendQueue *send_queue = NULL;
1246 gint i = 0, timeout = 0;
1248 info = (UpdateAccountInfo *) thr_user_data;
1249 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1251 /* Get account and set it into mail_operation */
1252 priv->account = g_object_ref (info->account);
1254 /* Get all the folders. We can do it synchronously because
1255 we're already running in a different thread than the UI */
1256 all_folders = get_all_folders_from_account (info->account, &(priv->error));
1258 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1262 /* Update status and notify. We need to call the notification
1263 with a source function in order to call it from the main
1264 loop. We need that in order not to get into trouble with
1265 Gtk+. We use a timeout in order to provide more status
1266 information, because the sync tinymail call does not
1267 provide it for the moment */
1268 timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1270 new_headers_array = g_ptr_array_new ();
1271 iter = tny_list_create_iterator (all_folders);
1273 while (!tny_iterator_is_done (iter) && !priv->error &&
1274 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1276 TnyFolderType folder_type;
1277 TnyFolder *folder = NULL;
1279 folder = TNY_FOLDER (tny_iterator_get_current (iter));
1280 folder_type = tny_folder_get_folder_type (folder);
1282 /* Refresh it only if it's the INBOX */
1283 if (folder_type == TNY_FOLDER_TYPE_INBOX) {
1284 InternalFolderObserver *observer = NULL;
1285 TnyIterator *new_headers_iter = NULL;
1287 /* Refresh the folder. Our observer receives
1288 * the new emails during folder refreshes, so
1289 * we can use observer->new_headers
1291 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1292 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1294 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1296 new_headers_iter = tny_list_create_iterator (observer->new_headers);
1297 while (!tny_iterator_is_done (new_headers_iter)) {
1298 TnyHeader *header = NULL;
1300 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1301 /* Apply per-message size limits */
1302 if (tny_header_get_message_size (header) < info->max_size)
1303 g_ptr_array_add (new_headers_array, g_object_ref (header));
1305 g_object_unref (header);
1306 tny_iterator_next (new_headers_iter);
1308 g_object_unref (new_headers_iter);
1310 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1311 g_object_unref (observer);
1313 /* We no not need to do it the first time,
1314 because it's automatically done by the tree
1316 if (G_LIKELY (!first_time))
1317 tny_folder_poke_status (folder);
1319 g_object_unref (folder);
1321 tny_iterator_next (iter);
1323 g_object_unref (G_OBJECT (iter));
1324 g_source_remove (timeout);
1326 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1327 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1328 new_headers_array->len > 0) {
1332 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1334 /* TODO: Ask the user, instead of just failing,
1335 * showing mail_nc_msg_count_limit_exceeded, with 'Get
1336 * all' and 'Newest only' buttons. */
1337 if (new_headers_array->len > info->retrieve_limit) {
1341 /* Should be get only the headers or the message as well? */
1342 if (g_ascii_strcasecmp (info->retrieve_type,
1343 MODEST_ACCOUNT_RETRIEVE_VALUE_HEADERS_ONLY) != 0) {
1345 priv->total = MIN (new_headers_array->len, info->retrieve_limit);
1346 while (msg_num < priv->total) {
1348 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1349 TnyFolder *folder = tny_header_get_folder (header);
1350 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1351 ModestMailOperationState *state;
1355 /* We can not just use the mail operation because the
1356 values of done and total could change before the
1358 state = modest_mail_operation_clone_state (info->mail_op);
1359 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1360 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1361 pair, (GDestroyNotify) modest_pair_free);
1363 g_object_unref (msg);
1364 g_object_unref (folder);
1371 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1374 /* Copy the headers to a list and free the array */
1375 new_headers = tny_simple_list_new ();
1376 for (i=0; i < new_headers_array->len; i++) {
1377 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1378 tny_list_append (new_headers, G_OBJECT (header));
1380 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1381 g_ptr_array_free (new_headers_array, FALSE);
1384 /* Perform send (if operation was not cancelled) */
1387 if (priv->account != NULL)
1388 g_object_unref (priv->account);
1389 priv->account = g_object_ref (info->transport_account);
1391 send_queue = modest_runtime_get_send_queue (info->transport_account);
1393 modest_tny_send_queue_try_to_send (send_queue);
1395 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1396 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1397 "cannot create a send queue for %s\n",
1398 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1399 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1402 /* Check if the operation was a success */
1404 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1406 /* Update the last updated key */
1407 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1408 set_last_updated_idle,
1409 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1410 (GDestroyNotify) g_free);
1415 if (info->callback) {
1416 UpdateAccountInfo *idle_info;
1418 /* This thread is not in the main lock */
1419 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1420 idle_info->mail_op = g_object_ref (info->mail_op);
1421 idle_info->new_headers = (new_headers) ? g_object_ref (new_headers) : NULL;
1422 idle_info->callback = info->callback;
1423 idle_info->user_data = info->user_data;
1424 g_idle_add (idle_update_account_cb, idle_info);
1427 /* Notify about operation end. Note that the info could be
1428 freed before this idle happens, but the mail operation will
1430 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1434 g_object_unref (new_headers);
1436 g_object_unref (all_folders);
1437 g_object_unref (info->account);
1438 g_object_unref (info->transport_account);
1439 g_free (info->retrieve_type);
1440 g_slice_free (UpdateAccountInfo, info);
1448 modest_mail_operation_update_account (ModestMailOperation *self,
1449 const gchar *account_name,
1450 UpdateAccountCallback callback,
1453 GThread *thread = NULL;
1454 UpdateAccountInfo *info = NULL;
1455 ModestMailOperationPrivate *priv = NULL;
1456 ModestAccountMgr *mgr = NULL;
1457 TnyStoreAccount *store_account = NULL;
1458 TnyTransportAccount *transport_account = NULL;
1460 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1461 g_return_val_if_fail (account_name, FALSE);
1463 /* Init mail operation. Set total and done to 0, and do not
1464 update them, this way the progress objects will know that
1465 we have no clue about the number of the objects */
1466 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1469 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1471 /* Get the store account */
1472 store_account = (TnyStoreAccount *)
1473 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1475 TNY_ACCOUNT_TYPE_STORE);
1477 if (!store_account) {
1478 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1479 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1480 "cannot get tny store account for %s\n", account_name);
1485 /* Get the transport account, we can not do it in the thread
1486 due to some problems with dbus */
1487 transport_account = (TnyTransportAccount *)
1488 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1490 if (!transport_account) {
1491 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1492 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1493 "cannot get tny transport account for %s\n", account_name);
1497 /* Create the helper object */
1498 info = g_slice_new (UpdateAccountInfo);
1499 info->mail_op = self;
1500 info->account = store_account;
1501 info->transport_account = transport_account;
1502 info->callback = callback;
1503 info->user_data = user_data;
1505 /* Get the message size limit */
1506 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1507 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1508 if (info->max_size == 0)
1509 info->max_size = G_MAXINT;
1511 info->max_size = info->max_size * KB;
1513 /* Get per-account retrieval type */
1514 mgr = modest_runtime_get_account_mgr ();
1515 info->retrieve_type = modest_account_mgr_get_retrieve_type (mgr, account_name);
1517 /* Get per-account message amount retrieval limit */
1518 info->retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, account_name);
1519 if (info->retrieve_limit == 0)
1520 info->retrieve_limit = G_MAXINT;
1522 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1524 /* Set account busy */
1525 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1526 priv->account_name = g_strdup(account_name);
1528 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1534 g_object_unref (store_account);
1535 if (transport_account)
1536 g_object_unref (transport_account);
1537 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1539 callback (self, NULL, user_data);
1541 modest_mail_operation_notify_end (self);
1545 /* ******************************************************************* */
1546 /* ************************** STORE ACTIONS ************************* */
1547 /* ******************************************************************* */
1551 modest_mail_operation_create_folder (ModestMailOperation *self,
1552 TnyFolderStore *parent,
1555 ModestMailOperationPrivate *priv;
1556 TnyFolder *new_folder = NULL;
1558 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1559 g_return_val_if_fail (name, NULL);
1561 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1563 /* Check for already existing folder */
1564 if (modest_tny_folder_has_subfolder_with_name (parent, name)) {
1565 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1566 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1567 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1568 _CS("ckdg_ib_folder_already_exists"));
1572 if (TNY_IS_FOLDER (parent)) {
1573 /* Check folder rules */
1574 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1575 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1576 /* Set status failed and set an error */
1577 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1578 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1579 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1580 _("mail_in_ui_folder_create_error"));
1584 if (!strcmp (name, " ") || strchr (name, '/')) {
1585 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1586 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1587 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1588 _("mail_in_ui_folder_create_error"));
1592 /* Create the folder */
1593 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1594 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1596 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1599 /* Notify about operation end */
1600 modest_mail_operation_notify_end (self);
1606 modest_mail_operation_remove_folder (ModestMailOperation *self,
1608 gboolean remove_to_trash)
1610 TnyAccount *account;
1611 ModestMailOperationPrivate *priv;
1612 ModestTnyFolderRules rules;
1614 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1615 g_return_if_fail (TNY_IS_FOLDER (folder));
1617 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1619 /* Check folder rules */
1620 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1621 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1622 /* Set status failed and set an error */
1623 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1624 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1625 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1626 _("mail_in_ui_folder_delete_error"));
1630 /* Get the account */
1631 account = modest_tny_folder_get_account (folder);
1632 priv->account = g_object_ref(account);
1634 /* Delete folder or move to trash */
1635 if (remove_to_trash) {
1636 TnyFolder *trash_folder = NULL;
1637 trash_folder = modest_tny_account_get_special_folder (account,
1638 TNY_FOLDER_TYPE_TRASH);
1639 /* TODO: error_handling */
1641 modest_mail_operation_xfer_folder (self, folder,
1642 TNY_FOLDER_STORE (trash_folder),
1644 g_object_unref (trash_folder);
1647 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1649 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1650 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1653 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1656 g_object_unref (G_OBJECT (parent));
1658 g_object_unref (G_OBJECT (account));
1661 /* Notify about operation end */
1662 modest_mail_operation_notify_end (self);
1666 transfer_folder_status_cb (GObject *obj,
1670 ModestMailOperation *self;
1671 ModestMailOperationPrivate *priv;
1672 ModestMailOperationState *state;
1673 XFerMsgAsyncHelper *helper;
1675 g_return_if_fail (status != NULL);
1676 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1678 helper = (XFerMsgAsyncHelper *) user_data;
1679 g_return_if_fail (helper != NULL);
1681 self = helper->mail_op;
1682 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1684 priv->done = status->position;
1685 priv->total = status->of_total;
1687 state = modest_mail_operation_clone_state (self);
1689 /* This is not a GDK lock because we are a Tinymail callback
1690 * which is already GDK locked by Tinymail */
1692 /* no gdk_threads_enter (), CHECKED */
1694 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1696 /* no gdk_threads_leave (), CHECKED */
1698 g_slice_free (ModestMailOperationState, state);
1703 transfer_folder_cb (TnyFolder *folder,
1705 TnyFolderStore *into,
1706 TnyFolder *new_folder,
1710 XFerMsgAsyncHelper *helper;
1711 ModestMailOperation *self = NULL;
1712 ModestMailOperationPrivate *priv = NULL;
1714 helper = (XFerMsgAsyncHelper *) user_data;
1715 g_return_if_fail (helper != NULL);
1717 self = helper->mail_op;
1718 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1721 priv->error = g_error_copy (err);
1723 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1724 } else if (cancelled) {
1725 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1726 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1727 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1728 _("Transference of %s was cancelled."),
1729 tny_folder_get_name (folder));
1732 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1735 /* Notify about operation end */
1736 modest_mail_operation_notify_end (self);
1738 /* If user defined callback function was defined, call it */
1739 if (helper->user_callback) {
1741 /* This is not a GDK lock because we are a Tinymail callback
1742 * which is already GDK locked by Tinymail */
1744 /* no gdk_threads_enter (), CHECKED */
1745 helper->user_callback (self, helper->user_data);
1746 /* no gdk_threads_leave () , CHECKED */
1750 g_object_unref (helper->mail_op);
1751 g_slice_free (XFerMsgAsyncHelper, helper);
1756 * This function checks if the new name is a valid name for our local
1757 * folders account. The new name could not be the same than then name
1758 * of any of the mandatory local folders
1760 * We can not rely on tinymail because tinymail does not check the
1761 * name of the virtual folders that the account could have in the case
1762 * that we're doing a rename (because it directly calls Camel which
1763 * knows nothing about our virtual folders).
1765 * In the case of an actual copy/move (i.e. move/copy a folder between
1766 * accounts) tinymail uses the tny_folder_store_create_account which
1767 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1768 * checks the new name of the folder, so this call in that case
1769 * wouldn't be needed. *But* NOTE that if tinymail changes its
1770 * implementation (if folder transfers within the same account is no
1771 * longer implemented as a rename) this call will allow Modest to work
1774 * If the new name is not valid, this function will set the status to
1775 * failed and will set also an error in the mail operation
1778 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1779 TnyFolderStore *into,
1780 const gchar *new_name)
1782 if (TNY_IS_ACCOUNT (into) &&
1783 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1784 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1786 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1787 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1788 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1789 _("ckdg_ib_folder_already_exists"));
1796 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1798 TnyFolderStore *parent,
1799 gboolean delete_original,
1800 XferAsyncUserCallback user_callback,
1803 ModestMailOperationPrivate *priv = NULL;
1804 ModestTnyFolderRules parent_rules = 0, rules;
1805 XFerMsgAsyncHelper *helper = NULL;
1806 const gchar *folder_name = NULL;
1807 const gchar *error_msg;
1809 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1810 g_return_if_fail (TNY_IS_FOLDER (folder));
1811 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1813 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1814 folder_name = tny_folder_get_name (folder);
1816 /* Set the error msg */
1817 error_msg = _("mail_in_ui_folder_move_target_error");
1819 /* Get account and set it into mail_operation */
1820 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1821 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1823 /* Get folder rules */
1824 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1825 if (TNY_IS_FOLDER (parent))
1826 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1828 /* Apply operation constraints */
1829 if ((gpointer) parent == (gpointer) folder ||
1830 (!TNY_IS_FOLDER_STORE (parent)) ||
1831 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1834 } else if (TNY_IS_FOLDER (parent) &&
1835 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1839 } else if (TNY_IS_FOLDER (parent) &&
1840 TNY_IS_FOLDER_STORE (folder) &&
1841 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1842 TNY_FOLDER_STORE (folder))) {
1843 /* Do not move a parent into a child */
1845 } else if (TNY_IS_FOLDER_STORE (parent) &&
1846 modest_tny_folder_has_subfolder_with_name (parent, folder_name)) {
1847 /* Check that the new folder name is not used by any
1850 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1851 /* Check that the new folder name is not used by any
1852 special local folder */
1855 /* Create the helper */
1856 helper = g_slice_new0 (XFerMsgAsyncHelper);
1857 helper->mail_op = g_object_ref (self);
1858 helper->dest_folder = NULL;
1859 helper->headers = NULL;
1860 helper->user_callback = user_callback;
1861 helper->user_data = user_data;
1863 /* Move/Copy folder */
1864 tny_folder_copy_async (folder,
1866 tny_folder_get_name (folder),
1869 transfer_folder_status_cb,
1875 /* Set status failed and set an error */
1876 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1877 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1878 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1881 /* Call the user callback if exists */
1883 user_callback (self, user_data);
1885 /* Notify the queue */
1886 modest_mail_operation_notify_end (self);
1890 modest_mail_operation_rename_folder (ModestMailOperation *self,
1894 ModestMailOperationPrivate *priv;
1895 ModestTnyFolderRules rules;
1896 XFerMsgAsyncHelper *helper;
1898 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1899 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1900 g_return_if_fail (name);
1902 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1904 /* Get account and set it into mail_operation */
1905 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1907 /* Check folder rules */
1908 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1909 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1910 /* Set status failed and set an error */
1911 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1912 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1913 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1914 _("FIXME: unable to rename"));
1916 /* Notify about operation end */
1917 modest_mail_operation_notify_end (self);
1918 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1919 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1920 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1921 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1922 _("FIXME: unable to rename"));
1923 /* Notify about operation end */
1924 modest_mail_operation_notify_end (self);
1926 TnyFolderStore *into;
1928 into = tny_folder_get_folder_store (folder);
1930 /* Check that the new folder name is not used by any
1931 special local folder */
1932 if (new_name_valid_if_local_account (priv, into, name)) {
1933 /* Create the helper */
1934 helper = g_slice_new0 (XFerMsgAsyncHelper);
1935 helper->mail_op = g_object_ref(self);
1936 helper->dest_folder = NULL;
1937 helper->headers = NULL;
1938 helper->user_callback = NULL;
1939 helper->user_data = NULL;
1941 /* Rename. Camel handles folder subscription/unsubscription */
1942 tny_folder_copy_async (folder, into, name, TRUE,
1944 transfer_folder_status_cb,
1947 modest_mail_operation_notify_end (self);
1949 g_object_unref (into);
1953 /* ******************************************************************* */
1954 /* ************************** MSG ACTIONS ************************* */
1955 /* ******************************************************************* */
1957 void modest_mail_operation_get_msg (ModestMailOperation *self,
1959 GetMsgAsyncUserCallback user_callback,
1962 GetMsgAsyncHelper *helper = NULL;
1964 ModestMailOperationPrivate *priv;
1966 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1967 g_return_if_fail (TNY_IS_HEADER (header));
1969 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1970 folder = tny_header_get_folder (header);
1972 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1974 /* Get message from folder */
1976 /* Get account and set it into mail_operation */
1977 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1979 /* Check for cached messages */
1980 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
1981 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1983 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1985 helper = g_slice_new0 (GetMsgAsyncHelper);
1986 helper->mail_op = self;
1987 helper->user_callback = user_callback;
1988 helper->user_data = user_data;
1989 helper->header = g_object_ref (header);
1991 // The callback's reference so that the mail op is not
1992 // finalized until the async operation is completed even if
1993 // the user canceled the request meanwhile.
1994 g_object_ref (G_OBJECT (helper->mail_op));
1996 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1998 g_object_unref (G_OBJECT (folder));
2000 /* Set status failed and set an error */
2001 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2002 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2003 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2004 _("Error trying to get a message. No folder found for header"));
2006 /* Notify the queue */
2007 modest_mail_operation_notify_end (self);
2012 get_msg_cb (TnyFolder *folder,
2018 GetMsgAsyncHelper *helper = NULL;
2019 ModestMailOperation *self = NULL;
2020 ModestMailOperationPrivate *priv = NULL;
2022 helper = (GetMsgAsyncHelper *) user_data;
2023 g_return_if_fail (helper != NULL);
2024 self = helper->mail_op;
2025 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2026 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2028 /* Check errors and cancel */
2030 priv->error = g_error_copy (error);
2031 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2032 } else if (cancelled) {
2033 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2034 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2035 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2036 _("Error trying to refresh the contents of %s"),
2037 tny_folder_get_name (folder));
2039 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2042 /* If user defined callback function was defined, call it even
2043 if the operation failed*/
2044 if (helper->user_callback) {
2045 /* This is not a GDK lock because we are a Tinymail callback
2046 * which is already GDK locked by Tinymail */
2048 /* no gdk_threads_enter (), CHECKED */
2049 helper->user_callback (self, helper->header, msg, helper->user_data);
2050 /* no gdk_threads_leave (), CHECKED */
2053 /* Notify about operation end */
2054 modest_mail_operation_notify_end (self);
2056 g_object_unref (helper->mail_op);
2057 g_object_unref (helper->header);
2058 g_slice_free (GetMsgAsyncHelper, helper);
2063 get_msg_status_cb (GObject *obj,
2067 GetMsgAsyncHelper *helper = NULL;
2068 ModestMailOperation *self;
2069 ModestMailOperationPrivate *priv;
2070 ModestMailOperationState *state;
2072 g_return_if_fail (status != NULL);
2073 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2075 helper = (GetMsgAsyncHelper *) user_data;
2076 g_return_if_fail (helper != NULL);
2078 self = helper->mail_op;
2079 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2084 state = modest_mail_operation_clone_state (self);
2085 state->bytes_done = status->position;
2086 state->bytes_total = status->of_total;
2088 /* This is not a GDK lock because we are a Tinymail callback
2089 * which is already GDK locked by Tinymail */
2091 /* no gdk_threads_enter (), CHECKED */
2092 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2093 /* no gdk_threads_leave (), CHECKED */
2095 g_slice_free (ModestMailOperationState, state);
2098 /****************************************************/
2100 ModestMailOperation *mail_op;
2102 GetMsgAsyncUserCallback user_callback;
2104 GDestroyNotify notify;
2108 GetMsgAsyncUserCallback user_callback;
2112 ModestMailOperation *mail_op;
2113 } NotifyGetMsgsInfo;
2117 * Used by get_msgs_full_thread to call the user_callback for each
2118 * message that has been read
2121 notify_get_msgs_full (gpointer data)
2123 NotifyGetMsgsInfo *info;
2125 info = (NotifyGetMsgsInfo *) data;
2127 /* This is a GDK lock because we are an idle callback and
2128 * because info->user_callback can contain Gtk+ code */
2130 gdk_threads_enter (); /* CHECKED */
2131 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2132 gdk_threads_leave (); /* CHECKED */
2134 g_slice_free (NotifyGetMsgsInfo, info);
2140 * Used by get_msgs_full_thread to free al the thread resources and to
2141 * call the destroy function for the passed user_data
2144 get_msgs_full_destroyer (gpointer data)
2146 GetFullMsgsInfo *info;
2148 info = (GetFullMsgsInfo *) data;
2152 /* This is a GDK lock because we are an idle callback and
2153 * because info->notify can contain Gtk+ code */
2155 gdk_threads_enter (); /* CHECKED */
2156 info->notify (info->user_data);
2157 gdk_threads_leave (); /* CHECKED */
2161 g_object_unref (info->headers);
2162 g_slice_free (GetFullMsgsInfo, info);
2168 get_msgs_full_thread (gpointer thr_user_data)
2170 GetFullMsgsInfo *info;
2171 ModestMailOperationPrivate *priv = NULL;
2172 TnyIterator *iter = NULL;
2174 info = (GetFullMsgsInfo *) thr_user_data;
2175 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2177 iter = tny_list_create_iterator (info->headers);
2178 while (!tny_iterator_is_done (iter)) {
2182 header = TNY_HEADER (tny_iterator_get_current (iter));
2183 folder = tny_header_get_folder (header);
2185 /* Check for cached messages */
2186 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2187 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2189 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2191 /* Get message from folder */
2194 /* The callback will call it per each header */
2195 msg = tny_folder_get_msg (folder, header, &(priv->error));
2198 ModestMailOperationState *state;
2203 /* notify progress */
2204 state = modest_mail_operation_clone_state (info->mail_op);
2205 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2206 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2207 pair, (GDestroyNotify) modest_pair_free);
2209 /* The callback is the responsible for
2210 freeing the message */
2211 if (info->user_callback) {
2212 NotifyGetMsgsInfo *info_notify;
2213 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2214 info_notify->user_callback = info->user_callback;
2215 info_notify->mail_op = info->mail_op;
2216 info_notify->header = g_object_ref (header);
2217 info_notify->msg = g_object_ref (msg);
2218 info_notify->user_data = info->user_data;
2219 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2220 notify_get_msgs_full,
2223 g_object_unref (msg);
2226 /* Set status failed and set an error */
2227 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2228 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2229 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2230 "Error trying to get a message. No folder found for header");
2234 g_object_unref (header);
2236 tny_iterator_next (iter);
2239 /* Set operation status */
2240 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2241 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2243 /* Notify about operation end */
2244 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2246 /* Free thread resources. Will be called after all previous idles */
2247 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2253 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2254 TnyList *header_list,
2255 GetMsgAsyncUserCallback user_callback,
2257 GDestroyNotify notify)
2259 TnyHeader *header = NULL;
2260 TnyFolder *folder = NULL;
2262 ModestMailOperationPrivate *priv = NULL;
2263 GetFullMsgsInfo *info = NULL;
2264 gboolean size_ok = TRUE;
2266 TnyIterator *iter = NULL;
2268 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2270 /* Init mail operation */
2271 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2272 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2274 priv->total = tny_list_get_length(header_list);
2276 /* Get account and set it into mail_operation */
2277 if (tny_list_get_length (header_list) >= 1) {
2278 iter = tny_list_create_iterator (header_list);
2279 header = TNY_HEADER (tny_iterator_get_current (iter));
2281 folder = tny_header_get_folder (header);
2283 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2285 g_object_unref (folder);
2288 g_object_unref (header);
2291 if (tny_list_get_length (header_list) == 1) {
2292 g_object_unref (iter);
2297 /* Get msg size limit */
2298 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2299 MODEST_CONF_MSG_SIZE_LIMIT,
2302 g_clear_error (&(priv->error));
2303 max_size = G_MAXINT;
2305 max_size = max_size * KB;
2308 /* Check message size limits. If there is only one message
2309 always retrieve it */
2311 while (!tny_iterator_is_done (iter) && size_ok) {
2312 header = TNY_HEADER (tny_iterator_get_current (iter));
2314 if (tny_header_get_message_size (header) >= max_size)
2316 g_object_unref (header);
2319 tny_iterator_next (iter);
2321 g_object_unref (iter);
2325 /* Create the info */
2326 info = g_slice_new0 (GetFullMsgsInfo);
2327 info->mail_op = self;
2328 info->user_callback = user_callback;
2329 info->user_data = user_data;
2330 info->headers = g_object_ref (header_list);
2331 info->notify = notify;
2333 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2335 /* Set status failed and set an error */
2336 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2337 /* FIXME: the error msg is different for pop */
2338 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2339 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2340 _("emev_ni_ui_imap_msg_size_exceed_error"));
2341 /* Remove from queue and free resources */
2342 modest_mail_operation_notify_end (self);
2350 modest_mail_operation_remove_msg (ModestMailOperation *self,
2352 gboolean remove_to_trash /*ignored*/)
2355 ModestMailOperationPrivate *priv;
2357 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2358 g_return_if_fail (TNY_IS_HEADER (header));
2360 if (remove_to_trash)
2361 g_warning ("remove to trash is not implemented");
2363 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2364 folder = tny_header_get_folder (header);
2366 /* Get account and set it into mail_operation */
2367 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2369 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2371 /* remove message from folder */
2372 tny_folder_remove_msg (folder, header, &(priv->error));
2374 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2375 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2377 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2378 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* FALSE --> don't expunge *\/ */
2379 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2380 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2381 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* TRUE --> dont expunge *\/ */
2382 tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2385 /* tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /\* TRUE --> expunge *\/ */
2386 tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2392 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2394 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2397 g_object_unref (G_OBJECT (folder));
2399 /* Notify about operation end */
2400 modest_mail_operation_notify_end (self);
2404 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2406 gboolean remove_to_trash /*ignored*/)
2409 ModestMailOperationPrivate *priv;
2410 TnyIterator *iter = NULL;
2411 TnyHeader *header = NULL;
2413 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2414 g_return_if_fail (TNY_IS_LIST (headers));
2416 if (remove_to_trash)
2417 g_warning ("remove to trash is not implemented");
2419 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2421 /* Get folder from first header and sync it */
2422 iter = tny_list_create_iterator (headers);
2423 header = TNY_HEADER (tny_iterator_get_current (iter));
2424 folder = tny_header_get_folder (header);
2426 /* Get account and set it into mail_operation */
2427 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2429 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2431 /* remove message from folder */
2432 tny_folder_remove_msgs (folder, headers, &(priv->error));
2434 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2435 TNY_IS_CAMEL_POP_FOLDER (folder))
2436 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> don't expunge */
2439 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2445 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2447 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2450 g_object_unref (header);
2451 g_object_unref (iter);
2452 g_object_unref (G_OBJECT (folder));
2454 /* Notify about operation end */
2455 modest_mail_operation_notify_end (self);
2460 transfer_msgs_status_cb (GObject *obj,
2464 XFerMsgAsyncHelper *helper = NULL;
2465 ModestMailOperation *self;
2466 ModestMailOperationPrivate *priv;
2467 ModestMailOperationState *state;
2470 g_return_if_fail (status != NULL);
2471 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2473 helper = (XFerMsgAsyncHelper *) user_data;
2474 g_return_if_fail (helper != NULL);
2476 self = helper->mail_op;
2477 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2479 priv->done = status->position;
2480 priv->total = status->of_total;
2482 state = modest_mail_operation_clone_state (self);
2484 /* This is not a GDK lock because we are a Tinymail callback and
2485 * Tinymail already acquires the Gdk lock */
2487 /* no gdk_threads_enter (), CHECKED */
2489 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2491 /* no gdk_threads_leave (), CHECKED */
2493 g_slice_free (ModestMailOperationState, state);
2498 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2500 XFerMsgAsyncHelper *helper;
2501 ModestMailOperation *self;
2502 ModestMailOperationPrivate *priv;
2503 TnyIterator *iter = NULL;
2504 TnyHeader *header = NULL;
2506 helper = (XFerMsgAsyncHelper *) user_data;
2507 self = helper->mail_op;
2509 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2512 priv->error = g_error_copy (err);
2514 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2515 } else if (cancelled) {
2516 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2517 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2518 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2519 _("Error trying to refresh the contents of %s"),
2520 tny_folder_get_name (folder));
2523 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2525 /* Update folder counts */
2526 tny_folder_poke_status (folder);
2527 tny_folder_poke_status (helper->dest_folder);
2531 /* Mark headers as deleted and seen */
2532 if ((helper->delete) &&
2533 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2534 iter = tny_list_create_iterator (helper->headers);
2535 while (!tny_iterator_is_done (iter)) {
2536 header = TNY_HEADER (tny_iterator_get_current (iter));
2537 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2538 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2539 g_object_unref (header);
2541 tny_iterator_next (iter);
2547 /* Notify about operation end */
2548 modest_mail_operation_notify_end (self);
2550 /* If user defined callback function was defined, call it */
2551 if (helper->user_callback) {
2552 /* This is not a GDK lock because we are a Tinymail callback and
2553 * Tinymail already acquires the Gdk lock */
2555 /* no gdk_threads_enter (), CHECKED */
2556 helper->user_callback (self, helper->user_data);
2557 /* no gdk_threads_leave (), CHECKED */
2561 if (helper->headers)
2562 g_object_unref (helper->headers);
2563 if (helper->dest_folder)
2564 g_object_unref (helper->dest_folder);
2565 if (helper->mail_op)
2566 g_object_unref (helper->mail_op);
2568 g_object_unref (folder);
2570 g_object_unref (iter);
2571 g_slice_free (XFerMsgAsyncHelper, helper);
2575 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2578 gboolean delete_original,
2579 XferAsyncUserCallback user_callback,
2582 ModestMailOperationPrivate *priv = NULL;
2583 TnyIterator *iter = NULL;
2584 TnyFolder *src_folder = NULL;
2585 XFerMsgAsyncHelper *helper = NULL;
2586 TnyHeader *header = NULL;
2587 ModestTnyFolderRules rules = 0;
2589 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2590 g_return_if_fail (TNY_IS_LIST (headers));
2591 g_return_if_fail (TNY_IS_FOLDER (folder));
2593 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2596 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2598 /* Apply folder rules */
2599 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2600 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2601 /* Set status failed and set an error */
2602 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2603 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2604 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2605 _CS("ckct_ib_unable_to_paste_here"));
2606 /* Notify the queue */
2607 modest_mail_operation_notify_end (self);
2611 /* Get source folder */
2612 iter = tny_list_create_iterator (headers);
2613 header = TNY_HEADER (tny_iterator_get_current (iter));
2615 src_folder = tny_header_get_folder (header);
2616 g_object_unref (header);
2619 g_object_unref (iter);
2621 /* Check folder source and destination */
2622 if (src_folder == folder) {
2623 /* Set status failed and set an error */
2624 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2625 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2626 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2627 _("mcen_ib_unable_to_copy_samefolder"));
2629 /* Notify the queue */
2630 modest_mail_operation_notify_end (self);
2633 g_object_unref (src_folder);
2637 /* Create the helper */
2638 helper = g_slice_new0 (XFerMsgAsyncHelper);
2639 helper->mail_op = g_object_ref(self);
2640 helper->dest_folder = g_object_ref(folder);
2641 helper->headers = g_object_ref(headers);
2642 helper->user_callback = user_callback;
2643 helper->user_data = user_data;
2644 helper->delete = delete_original;
2646 /* Get account and set it into mail_operation */
2647 priv->account = modest_tny_folder_get_account (src_folder);
2649 /* Transfer messages */
2650 tny_folder_transfer_msgs_async (src_folder,
2655 transfer_msgs_status_cb,
2661 on_refresh_folder (TnyFolder *folder,
2666 RefreshAsyncHelper *helper = NULL;
2667 ModestMailOperation *self = NULL;
2668 ModestMailOperationPrivate *priv = NULL;
2670 helper = (RefreshAsyncHelper *) user_data;
2671 self = helper->mail_op;
2672 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2674 g_return_if_fail(priv!=NULL);
2677 priv->error = g_error_copy (error);
2678 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2679 printf("DEBUG: %s: Operation error:\n %s", __FUNCTION__,
2685 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2686 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2687 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2688 _("Error trying to refresh the contents of %s"),
2689 tny_folder_get_name (folder));
2690 printf("DEBUG: %s: Operation cancelled.\n", __FUNCTION__);
2694 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2696 /* Call user defined callback, if it exists */
2697 if (helper->user_callback) {
2699 /* This is not a GDK lock because we are a Tinymail callback and
2700 * Tinymail already acquires the Gdk lock */
2701 helper->user_callback (self, folder, helper->user_data);
2706 g_slice_free (RefreshAsyncHelper, helper);
2708 /* Notify about operation end */
2709 modest_mail_operation_notify_end (self);
2710 g_object_unref(self);
2714 on_refresh_folder_status_update (GObject *obj,
2718 RefreshAsyncHelper *helper = NULL;
2719 ModestMailOperation *self = NULL;
2720 ModestMailOperationPrivate *priv = NULL;
2721 ModestMailOperationState *state;
2723 g_return_if_fail (user_data != NULL);
2724 g_return_if_fail (status != NULL);
2725 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2727 helper = (RefreshAsyncHelper *) user_data;
2728 self = helper->mail_op;
2729 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2731 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2733 priv->done = status->position;
2734 priv->total = status->of_total;
2736 state = modest_mail_operation_clone_state (self);
2738 /* This is not a GDK lock because we are a Tinymail callback and
2739 * Tinymail already acquires the Gdk lock */
2740 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2742 g_slice_free (ModestMailOperationState, state);
2746 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2748 RefreshAsyncUserCallback user_callback,
2751 ModestMailOperationPrivate *priv = NULL;
2752 RefreshAsyncHelper *helper = NULL;
2754 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2756 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2758 /* Get account and set it into mail_operation */
2759 priv->account = modest_tny_folder_get_account (folder);
2761 /* Create the helper */
2762 helper = g_slice_new0 (RefreshAsyncHelper);
2763 helper->mail_op = g_object_ref(self);
2764 helper->user_callback = user_callback;
2765 helper->user_data = user_data;
2767 /* Refresh the folder. TODO: tinymail could issue a status
2768 updates before the callback call then this could happen. We
2769 must review the design */
2770 tny_folder_refresh_async (folder,
2772 on_refresh_folder_status_update,
2778 * It's used by the mail operation queue to notify the observers
2779 * attached to that signal that the operation finished. We need to use
2780 * that because tinymail does not give us the progress of a given
2781 * operation when it finishes (it directly calls the operation
2785 modest_mail_operation_notify_end (ModestMailOperation *self)
2787 ModestMailOperationState *state;
2788 ModestMailOperationPrivate *priv = NULL;
2790 g_return_if_fail (self);
2792 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2794 /* Set the account back to not busy */
2795 if (priv->account_name) {
2796 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2797 priv->account_name, FALSE);
2798 g_free(priv->account_name);
2799 priv->account_name = NULL;
2802 /* Notify the observers about the mail operation end */
2803 /* We do not wrapp this emission because we assume that this
2804 function is always called from within the main lock */
2805 state = modest_mail_operation_clone_state (self);
2806 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2807 g_slice_free (ModestMailOperationState, state);