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_start (ModestMailOperation *self);
85 static void modest_mail_operation_notify_end (ModestMailOperation *self);
87 enum _ModestMailOperationSignals
89 PROGRESS_CHANGED_SIGNAL,
90 OPERATION_STARTED_SIGNAL,
91 OPERATION_FINISHED_SIGNAL,
95 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
96 struct _ModestMailOperationPrivate {
102 ErrorCheckingUserCallback error_checking;
103 gpointer error_checking_user_data;
104 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
105 ModestMailOperationStatus status;
106 ModestMailOperationTypeOperation op_type;
109 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
110 MODEST_TYPE_MAIL_OPERATION, \
111 ModestMailOperationPrivate))
113 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
114 priv->status = new_status;\
117 typedef struct _GetMsgAsyncHelper {
118 ModestMailOperation *mail_op;
120 GetMsgAsyncUserCallback user_callback;
124 typedef struct _RefreshAsyncHelper {
125 ModestMailOperation *mail_op;
126 RefreshAsyncUserCallback user_callback;
128 } RefreshAsyncHelper;
130 typedef struct _XFerMsgAsyncHelper
132 ModestMailOperation *mail_op;
134 TnyFolder *dest_folder;
135 XferAsyncUserCallback user_callback;
138 } XFerMsgAsyncHelper;
140 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
144 static void modest_mail_operation_create_msg (ModestMailOperation *self,
145 const gchar *from, const gchar *to,
146 const gchar *cc, const gchar *bcc,
147 const gchar *subject, const gchar *plain_body,
148 const gchar *html_body, const GList *attachments_list,
149 const GList *images_list,
150 TnyHeaderFlags priority_flags,
151 ModestMailOperationCreateMsgCallback callback,
154 static gboolean idle_notify_queue (gpointer data);
157 ModestMailOperation *mail_op;
165 GList *attachments_list;
167 TnyHeaderFlags priority_flags;
168 ModestMailOperationCreateMsgCallback callback;
174 ModestMailOperation *mail_op;
176 ModestMailOperationCreateMsgCallback callback;
181 static GObjectClass *parent_class = NULL;
183 static guint signals[NUM_SIGNALS] = {0};
186 modest_mail_operation_get_type (void)
188 static GType my_type = 0;
190 static const GTypeInfo my_info = {
191 sizeof(ModestMailOperationClass),
192 NULL, /* base init */
193 NULL, /* base finalize */
194 (GClassInitFunc) modest_mail_operation_class_init,
195 NULL, /* class finalize */
196 NULL, /* class data */
197 sizeof(ModestMailOperation),
199 (GInstanceInitFunc) modest_mail_operation_init,
202 my_type = g_type_register_static (G_TYPE_OBJECT,
203 "ModestMailOperation",
210 modest_mail_operation_class_init (ModestMailOperationClass *klass)
212 GObjectClass *gobject_class;
213 gobject_class = (GObjectClass*) klass;
215 parent_class = g_type_class_peek_parent (klass);
216 gobject_class->finalize = modest_mail_operation_finalize;
218 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
221 * ModestMailOperation::progress-changed
222 * @self: the #MailOperation that emits the signal
223 * @user_data: user data set when the signal handler was connected
225 * Emitted when the progress of a mail operation changes
227 signals[PROGRESS_CHANGED_SIGNAL] =
228 g_signal_new ("progress-changed",
229 G_TYPE_FROM_CLASS (gobject_class),
231 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
233 g_cclosure_marshal_VOID__POINTER,
234 G_TYPE_NONE, 1, G_TYPE_POINTER);
238 * This signal is issued whenever a mail operation starts, and
239 * starts mean when the tinymail operation is issued. This
240 * means that it could happen that something wrong happens and
241 * the tinymail function is never called. In this situation a
242 * operation-finished will be issued without any
245 signals[OPERATION_STARTED_SIGNAL] =
246 g_signal_new ("operation-started",
247 G_TYPE_FROM_CLASS (gobject_class),
249 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
251 g_cclosure_marshal_VOID__VOID,
256 * This signal is issued whenever a mail operation
257 * finishes. Note that this signal could be issued without any
258 * previous "operation-started" signal, because this last one
259 * is only issued when the tinymail operation is successfully
262 signals[OPERATION_FINISHED_SIGNAL] =
263 g_signal_new ("operation-finished",
264 G_TYPE_FROM_CLASS (gobject_class),
266 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
268 g_cclosure_marshal_VOID__VOID,
273 modest_mail_operation_init (ModestMailOperation *obj)
275 ModestMailOperationPrivate *priv;
277 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
279 priv->account = NULL;
280 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
281 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
286 priv->error_checking = NULL;
287 priv->error_checking_user_data = NULL;
291 modest_mail_operation_finalize (GObject *obj)
293 ModestMailOperationPrivate *priv;
295 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
300 g_error_free (priv->error);
304 g_object_unref (priv->source);
308 g_object_unref (priv->account);
309 priv->account = NULL;
313 G_OBJECT_CLASS(parent_class)->finalize (obj);
317 modest_mail_operation_new (GObject *source)
319 ModestMailOperation *obj;
320 ModestMailOperationPrivate *priv;
322 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
323 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
326 priv->source = g_object_ref(source);
332 modest_mail_operation_new_with_error_handling (GObject *source,
333 ErrorCheckingUserCallback error_handler,
335 ErrorCheckingUserDataDestroyer error_handler_destroyer)
337 ModestMailOperation *obj;
338 ModestMailOperationPrivate *priv;
340 obj = modest_mail_operation_new (source);
341 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
343 g_return_val_if_fail (error_handler != NULL, obj);
344 priv->error_checking = error_handler;
345 priv->error_checking_user_data = user_data;
346 priv->error_checking_user_data_destroyer = error_handler_destroyer;
352 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
354 ModestMailOperationPrivate *priv;
356 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
357 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
359 /* Call the user callback */
360 if (priv->error_checking != NULL)
361 priv->error_checking (self, priv->error_checking_user_data);
365 ModestMailOperationTypeOperation
366 modest_mail_operation_get_type_operation (ModestMailOperation *self)
368 ModestMailOperationPrivate *priv;
370 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
372 return priv->op_type;
376 modest_mail_operation_is_mine (ModestMailOperation *self,
379 ModestMailOperationPrivate *priv;
381 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
382 if (priv->source == NULL) return FALSE;
384 return priv->source == me;
388 modest_mail_operation_get_source (ModestMailOperation *self)
390 ModestMailOperationPrivate *priv;
392 g_return_val_if_fail (self, NULL);
394 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
396 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
400 return (priv->source) ? g_object_ref (priv->source) : NULL;
403 ModestMailOperationStatus
404 modest_mail_operation_get_status (ModestMailOperation *self)
406 ModestMailOperationPrivate *priv;
408 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
409 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
410 MODEST_MAIL_OPERATION_STATUS_INVALID);
412 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
414 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
415 return MODEST_MAIL_OPERATION_STATUS_INVALID;
422 modest_mail_operation_get_error (ModestMailOperation *self)
424 ModestMailOperationPrivate *priv;
426 g_return_val_if_fail (self, NULL);
427 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
429 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
432 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
440 modest_mail_operation_cancel (ModestMailOperation *self)
442 ModestMailOperationPrivate *priv;
443 gboolean canceled = FALSE;
445 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
447 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
449 /* Note that if we call cancel with an already canceled mail
450 operation the progress changed signal won't be emitted */
451 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
455 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
457 /* Cancel the mail operation. We need to wrap it between this
458 start/stop operations to allow following calls to the
460 g_return_val_if_fail (priv->account, FALSE);
461 tny_account_cancel (priv->account);
467 modest_mail_operation_get_task_done (ModestMailOperation *self)
469 ModestMailOperationPrivate *priv;
471 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
473 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
478 modest_mail_operation_get_task_total (ModestMailOperation *self)
480 ModestMailOperationPrivate *priv;
482 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
484 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
489 modest_mail_operation_is_finished (ModestMailOperation *self)
491 ModestMailOperationPrivate *priv;
492 gboolean retval = FALSE;
494 if (!MODEST_IS_MAIL_OPERATION (self)) {
495 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
499 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
501 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
502 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
503 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
504 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
514 * Creates an image of the current state of a mail operation, the
515 * caller must free it
517 static ModestMailOperationState *
518 modest_mail_operation_clone_state (ModestMailOperation *self)
520 ModestMailOperationState *state;
521 ModestMailOperationPrivate *priv;
523 /* FIXME: this should be fixed properly
525 * in some cases, priv was NULL, so checking here to
528 g_return_val_if_fail (self, NULL);
529 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
530 g_return_val_if_fail (priv, NULL);
535 state = g_slice_new (ModestMailOperationState);
537 state->status = priv->status;
538 state->op_type = priv->op_type;
539 state->done = priv->done;
540 state->total = priv->total;
541 state->finished = modest_mail_operation_is_finished (self);
542 state->bytes_done = 0;
543 state->bytes_total = 0;
548 /* ******************************************************************* */
549 /* ************************** SEND ACTIONS ************************* */
550 /* ******************************************************************* */
553 modest_mail_operation_send_mail (ModestMailOperation *self,
554 TnyTransportAccount *transport_account,
557 TnySendQueue *send_queue = NULL;
558 ModestMailOperationPrivate *priv;
560 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
561 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
562 g_return_if_fail (TNY_IS_MSG (msg));
564 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
566 /* Get account and set it into mail_operation */
567 priv->account = g_object_ref (transport_account);
571 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
572 if (!TNY_IS_SEND_QUEUE(send_queue)) {
573 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
574 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
575 "modest: could not find send queue for account\n");
576 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
579 /* Add the msg to the queue */
580 modest_mail_operation_notify_start (self);
581 modest_tny_send_queue_add (MODEST_TNY_SEND_QUEUE(send_queue),
585 /* TODO: we're setting always success, do the check in
587 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
590 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)
591 modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
593 /* TODO: do this in the handler of the "msg-sent"
594 signal.Notify about operation end */
595 modest_mail_operation_notify_end (self);
599 idle_create_msg_cb (gpointer idle_data)
601 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
603 /* This is a GDK lock because we are an idle callback and
604 * info->callback can contain Gtk+ code */
606 gdk_threads_enter (); /* CHECKED */
607 info->callback (info->mail_op, info->msg, info->userdata);
609 g_object_unref (info->mail_op);
611 g_object_unref (info->msg);
612 g_slice_free (CreateMsgIdleInfo, info);
613 gdk_threads_leave (); /* CHECKED */
619 create_msg_thread (gpointer thread_data)
621 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
622 TnyMsg *new_msg = NULL;
623 ModestMailOperationPrivate *priv;
625 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
626 if (info->html_body == NULL) {
627 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
628 info->bcc, info->subject, info->plain_body,
629 info->attachments_list);
631 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
632 info->bcc, info->subject, info->html_body,
633 info->plain_body, info->attachments_list,
639 TnyHeaderFlags flags = 0;
641 /* Set priority flags in message */
642 header = tny_msg_get_header (new_msg);
643 if (info->priority_flags != 0)
644 flags |= info->priority_flags;
646 /* Set attachment flags in message */
647 if (info->attachments_list != NULL)
648 flags |= TNY_HEADER_FLAG_ATTACHMENTS;
650 tny_header_set_flags (header, flags);
651 g_object_unref (G_OBJECT(header));
653 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
654 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
655 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
656 "modest: failed to create a new msg\n");
664 g_free (info->plain_body);
665 g_free (info->html_body);
666 g_free (info->subject);
667 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
668 g_list_free (info->attachments_list);
669 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
670 g_list_free (info->images_list);
672 if (info->callback) {
673 CreateMsgIdleInfo *idle_info;
674 idle_info = g_slice_new0 (CreateMsgIdleInfo);
675 idle_info->mail_op = g_object_ref (info->mail_op);
676 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
677 idle_info->callback = info->callback;
678 idle_info->userdata = info->userdata;
679 g_idle_add (idle_create_msg_cb, idle_info);
681 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
684 g_object_unref (info->mail_op);
685 g_slice_free (CreateMsgInfo, info);
690 modest_mail_operation_create_msg (ModestMailOperation *self,
691 const gchar *from, const gchar *to,
692 const gchar *cc, const gchar *bcc,
693 const gchar *subject, const gchar *plain_body,
694 const gchar *html_body,
695 const GList *attachments_list,
696 const GList *images_list,
697 TnyHeaderFlags priority_flags,
698 ModestMailOperationCreateMsgCallback callback,
701 CreateMsgInfo *info = NULL;
703 info = g_slice_new0 (CreateMsgInfo);
704 info->mail_op = g_object_ref (self);
706 info->from = g_strdup (from);
707 info->to = g_strdup (to);
708 info->cc = g_strdup (cc);
709 info->bcc = g_strdup (bcc);
710 info->subject = g_strdup (subject);
711 info->plain_body = g_strdup (plain_body);
712 info->html_body = g_strdup (html_body);
713 info->attachments_list = g_list_copy ((GList *) attachments_list);
714 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
715 info->images_list = g_list_copy ((GList *) images_list);
716 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
717 info->priority_flags = priority_flags;
719 info->callback = callback;
720 info->userdata = userdata;
722 g_thread_create (create_msg_thread, info, FALSE, NULL);
727 TnyTransportAccount *transport_account;
732 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
736 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
737 TnyFolder *draft_folder = NULL;
738 TnyFolder *outbox_folder = NULL;
746 /* Call mail operation */
747 modest_mail_operation_send_mail (self, info->transport_account, msg);
749 /* Remove old mail from its source folder */
750 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
751 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_OUTBOX);
752 if (info->draft_msg != NULL) {
753 TnyFolder *folder = NULL;
754 TnyFolder *src_folder = NULL;
755 TnyFolderType folder_type;
756 folder = tny_msg_get_folder (info->draft_msg);
757 if (folder == NULL) goto end;
758 folder_type = modest_tny_folder_guess_folder_type (folder);
759 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
760 src_folder = outbox_folder;
762 src_folder = draft_folder;
764 /* Note: This can fail (with a warning) if the message is not really already in a folder,
765 * because this function requires it to have a UID. */
766 header = tny_msg_get_header (info->draft_msg);
767 tny_folder_remove_msg (src_folder, header, NULL);
769 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
770 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
772 g_object_unref (header);
773 g_object_unref (folder);
780 g_object_unref (info->draft_msg);
782 g_object_unref (draft_folder);
784 g_object_unref (outbox_folder);
785 if (info->transport_account)
786 g_object_unref (info->transport_account);
787 g_slice_free (SendNewMailInfo, info);
788 modest_mail_operation_notify_end (self);
792 modest_mail_operation_send_new_mail (ModestMailOperation *self,
793 TnyTransportAccount *transport_account,
795 const gchar *from, const gchar *to,
796 const gchar *cc, const gchar *bcc,
797 const gchar *subject, const gchar *plain_body,
798 const gchar *html_body,
799 const GList *attachments_list,
800 const GList *images_list,
801 TnyHeaderFlags priority_flags)
803 ModestMailOperationPrivate *priv = NULL;
804 SendNewMailInfo *info;
806 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
807 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
809 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
810 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
811 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
813 /* Check parametters */
815 /* Set status failed and set an error */
816 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
817 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
818 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
819 _("Error trying to send a mail. You need to set at least one recipient"));
822 info = g_slice_new0 (SendNewMailInfo);
823 info->transport_account = transport_account;
824 if (transport_account)
825 g_object_ref (transport_account);
826 info->draft_msg = draft_msg;
828 g_object_ref (draft_msg);
831 modest_mail_operation_notify_start (self);
832 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
833 attachments_list, images_list, priority_flags,
834 modest_mail_operation_send_new_mail_cb, info);
840 TnyTransportAccount *transport_account;
842 SaveToDraftstCallback callback;
847 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
851 TnyFolder *src_folder = NULL;
852 TnyFolder *drafts = NULL;
853 TnyHeader *header = NULL;
854 ModestMailOperationPrivate *priv = NULL;
855 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
857 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
860 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
861 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
862 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
863 "modest: failed to create a new msg\n");
867 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
868 TNY_FOLDER_TYPE_DRAFTS);
870 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
871 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
872 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
873 "modest: failed to create a new msg\n");
878 tny_folder_add_msg (drafts, msg, &(priv->error));
880 if ((!priv->error) && (info->draft_msg != NULL)) {
881 header = tny_msg_get_header (info->draft_msg);
882 src_folder = tny_header_get_folder (header);
884 /* Remove the old draft */
885 tny_folder_remove_msg (src_folder, header, NULL);
887 /* Synchronize to expunge and to update the msg counts */
888 tny_folder_sync_async (drafts, TRUE, NULL, NULL, NULL);
889 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
891 g_object_unref (header);
895 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
897 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
900 /* Call the user callback */
902 info->callback (self, msg, info->user_data);
905 g_object_unref (G_OBJECT(drafts));
907 g_object_unref (G_OBJECT(src_folder));
909 g_object_unref (G_OBJECT (info->draft_msg));
910 if (info->transport_account)
911 g_object_unref (G_OBJECT(info->transport_account));
912 g_slice_free (SaveToDraftsInfo, info);
914 modest_mail_operation_notify_end (self);
918 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
919 TnyTransportAccount *transport_account,
921 const gchar *from, const gchar *to,
922 const gchar *cc, const gchar *bcc,
923 const gchar *subject, const gchar *plain_body,
924 const gchar *html_body,
925 const GList *attachments_list,
926 const GList *images_list,
927 TnyHeaderFlags priority_flags,
928 SaveToDraftstCallback callback,
931 ModestMailOperationPrivate *priv = NULL;
932 SaveToDraftsInfo *info = NULL;
934 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
935 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
937 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
939 /* Get account and set it into mail_operation */
940 priv->account = g_object_ref (transport_account);
941 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
943 info = g_slice_new0 (SaveToDraftsInfo);
944 info->transport_account = g_object_ref (transport_account);
945 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
946 info->callback = callback;
947 info->user_data = user_data;
949 modest_mail_operation_notify_start (self);
950 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
951 attachments_list, images_list, priority_flags,
952 modest_mail_operation_save_to_drafts_cb, info);
957 ModestMailOperation *mail_op;
958 TnyStoreAccount *account;
959 TnyTransportAccount *transport_account;
962 gchar *retrieve_type;
964 UpdateAccountCallback callback;
966 TnyList *new_headers;
971 ModestMailOperation *mail_op;
972 TnyMimePart *mime_part;
974 GetMimePartSizeCallback callback;
976 } GetMimePartSizeInfo;
978 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
979 /* We use this folder observer to track the headers that have been
980 * added to a folder */
983 TnyList *new_headers;
984 } InternalFolderObserver;
988 } InternalFolderObserverClass;
990 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
992 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
993 internal_folder_observer,
995 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
999 foreach_add_item (gpointer header, gpointer user_data)
1001 tny_list_prepend (TNY_LIST (user_data),
1002 g_object_ref (G_OBJECT (header)));
1005 /* This is the method that looks for new messages in a folder */
1007 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1009 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1011 TnyFolderChangeChanged changed;
1013 changed = tny_folder_change_get_changed (change);
1015 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1018 /* Get added headers */
1019 list = tny_simple_list_new ();
1020 tny_folder_change_get_added_headers (change, list);
1022 /* Add them to the folder observer */
1023 tny_list_foreach (list, foreach_add_item,
1024 derived->new_headers);
1026 g_object_unref (G_OBJECT (list));
1031 internal_folder_observer_init (InternalFolderObserver *self)
1033 self->new_headers = tny_simple_list_new ();
1036 internal_folder_observer_finalize (GObject *object)
1038 InternalFolderObserver *self;
1040 self = (InternalFolderObserver *) object;
1041 g_object_unref (self->new_headers);
1043 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1046 tny_folder_observer_init (TnyFolderObserverIface *iface)
1048 iface->update_func = internal_folder_observer_update;
1051 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1053 GObjectClass *object_class;
1055 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1056 object_class = (GObjectClass*) klass;
1057 object_class->finalize = internal_folder_observer_finalize;
1063 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
1066 TnyList *folders = tny_simple_list_new ();
1068 tny_folder_store_get_folders (store, folders, query, NULL);
1069 iter = tny_list_create_iterator (folders);
1071 while (!tny_iterator_is_done (iter)) {
1073 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1075 tny_list_prepend (all_folders, G_OBJECT (folder));
1076 recurse_folders (folder, query, all_folders);
1077 g_object_unref (G_OBJECT (folder));
1080 tny_iterator_next (iter);
1082 g_object_unref (G_OBJECT (iter));
1083 g_object_unref (G_OBJECT (folders));
1087 * Issues the "progress-changed" signal. The timer won't be removed,
1088 * so you must call g_source_remove to stop the signal emission
1091 idle_notify_progress (gpointer data)
1093 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1094 ModestMailOperationState *state;
1096 state = modest_mail_operation_clone_state (mail_op);
1098 /* This is a GDK lock because we are an idle callback and
1099 * the handlers of this signal can contain Gtk+ code */
1101 gdk_threads_enter (); /* CHECKED */
1102 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1103 gdk_threads_leave (); /* CHECKED */
1105 g_slice_free (ModestMailOperationState, state);
1111 * Issues the "progress-changed" signal and removes the timer. It uses
1112 * a lock to ensure that the progress information of the mail
1113 * operation is not modified while there are notifications pending
1116 idle_notify_progress_once (gpointer data)
1120 pair = (ModestPair *) data;
1122 /* This is a GDK lock because we are an idle callback and
1123 * the handlers of this signal can contain Gtk+ code */
1125 gdk_threads_enter (); /* CHECKED */
1126 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1127 gdk_threads_leave (); /* CHECKED */
1129 /* Free the state and the reference to the mail operation */
1130 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1131 g_object_unref (pair->first);
1137 * Used to notify the queue from the main
1138 * loop. We call it inside an idle call to achieve that
1141 idle_notify_queue (gpointer data)
1143 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1145 /* Do not need to block, the notify end will do it for us */
1146 modest_mail_operation_notify_end (mail_op);
1147 g_object_unref (mail_op);
1153 compare_headers_by_date (gconstpointer a,
1156 TnyHeader **header1, **header2;
1157 time_t sent1, sent2;
1159 header1 = (TnyHeader **) a;
1160 header2 = (TnyHeader **) b;
1162 sent1 = tny_header_get_date_sent (*header1);
1163 sent2 = tny_header_get_date_sent (*header2);
1165 /* We want the most recent ones (greater time_t) at the
1174 set_last_updated_idle (gpointer data)
1177 /* This is a GDK lock because we are an idle callback and
1178 * modest_account_mgr_set_last_updated can issue Gtk+ code */
1180 gdk_threads_enter (); /* CHECKED - please recheck */
1182 /* It does not matter if the time is not exactly the same than
1183 the time when this idle was called, it's just an
1184 approximation and it won't be very different */
1186 modest_account_mgr_set_last_updated (modest_runtime_get_account_mgr (),
1190 gdk_threads_leave (); /* CHECKED - please recheck */
1196 idle_update_account_cb (gpointer data)
1198 UpdateAccountInfo *idle_info;
1200 idle_info = (UpdateAccountInfo *) data;
1202 /* This is a GDK lock because we are an idle callback and
1203 * idle_info->callback can contain Gtk+ code */
1205 gdk_threads_enter (); /* CHECKED */
1206 idle_info->callback (idle_info->mail_op,
1207 idle_info->new_headers,
1208 idle_info->user_data);
1209 gdk_threads_leave (); /* CHECKED */
1212 g_object_unref (idle_info->mail_op);
1213 if (idle_info->new_headers)
1214 g_object_unref (idle_info->new_headers);
1221 get_all_folders_from_account (TnyStoreAccount *account,
1224 TnyList *all_folders = NULL;
1225 TnyIterator *iter = NULL;
1226 TnyFolderStoreQuery *query = NULL;
1228 all_folders = tny_simple_list_new ();
1229 query = tny_folder_store_query_new ();
1230 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1231 tny_folder_store_get_folders (TNY_FOLDER_STORE (account),
1238 g_object_unref (all_folders);
1242 iter = tny_list_create_iterator (all_folders);
1243 while (!tny_iterator_is_done (iter)) {
1244 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1246 recurse_folders (folder, query, all_folders);
1247 g_object_unref (folder);
1249 tny_iterator_next (iter);
1251 g_object_unref (G_OBJECT (iter));
1258 update_account_thread (gpointer thr_user_data)
1260 static gboolean first_time = TRUE;
1261 UpdateAccountInfo *info = NULL;
1262 TnyList *all_folders = NULL, *new_headers = NULL;
1263 GPtrArray *new_headers_array = NULL;
1264 TnyIterator *iter = NULL;
1265 ModestMailOperationPrivate *priv = NULL;
1266 ModestTnySendQueue *send_queue = NULL;
1267 gint i = 0, timeout = 0;
1269 info = (UpdateAccountInfo *) thr_user_data;
1270 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1272 /* Get account and set it into mail_operation */
1273 priv->account = g_object_ref (info->account);
1275 /* Get all the folders. We can do it synchronously because
1276 we're already running in a different thread than the UI */
1277 all_folders = get_all_folders_from_account (info->account, &(priv->error));
1279 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1283 /* Update status and notify. We need to call the notification
1284 with a source function in order to call it from the main
1285 loop. We need that in order not to get into trouble with
1286 Gtk+. We use a timeout in order to provide more status
1287 information, because the sync tinymail call does not
1288 provide it for the moment */
1289 timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1291 new_headers_array = g_ptr_array_new ();
1292 iter = tny_list_create_iterator (all_folders);
1294 while (!tny_iterator_is_done (iter) && !priv->error &&
1295 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1297 TnyFolderType folder_type;
1298 TnyFolder *folder = NULL;
1300 folder = TNY_FOLDER (tny_iterator_get_current (iter));
1301 folder_type = tny_folder_get_folder_type (folder);
1303 /* Refresh it only if it's the INBOX */
1304 if (folder_type == TNY_FOLDER_TYPE_INBOX) {
1305 InternalFolderObserver *observer = NULL;
1306 TnyIterator *new_headers_iter = NULL;
1308 /* Refresh the folder. Our observer receives
1309 * the new emails during folder refreshes, so
1310 * we can use observer->new_headers
1312 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1313 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1315 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1317 new_headers_iter = tny_list_create_iterator (observer->new_headers);
1318 while (!tny_iterator_is_done (new_headers_iter)) {
1319 TnyHeader *header = NULL;
1321 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1322 /* Apply per-message size limits */
1323 if (tny_header_get_message_size (header) < info->max_size)
1324 g_ptr_array_add (new_headers_array, g_object_ref (header));
1326 g_object_unref (header);
1327 tny_iterator_next (new_headers_iter);
1329 g_object_unref (new_headers_iter);
1331 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1332 g_object_unref (observer);
1334 /* We no not need to do it the first time,
1335 because it's automatically done by the tree
1337 if (G_LIKELY (!first_time))
1338 tny_folder_poke_status (folder);
1340 g_object_unref (folder);
1342 tny_iterator_next (iter);
1344 g_object_unref (G_OBJECT (iter));
1345 g_source_remove (timeout);
1347 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1348 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1349 new_headers_array->len > 0) {
1353 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1355 /* TODO: Ask the user, instead of just failing,
1356 * showing mail_nc_msg_count_limit_exceeded, with 'Get
1357 * all' and 'Newest only' buttons. */
1358 if (new_headers_array->len > info->retrieve_limit) {
1362 /* Should be get only the headers or the message as well? */
1363 if (g_ascii_strcasecmp (info->retrieve_type,
1364 MODEST_ACCOUNT_RETRIEVE_VALUE_HEADERS_ONLY) != 0) {
1366 priv->total = MIN (new_headers_array->len, info->retrieve_limit);
1367 while (msg_num < priv->total) {
1369 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1370 TnyFolder *folder = tny_header_get_folder (header);
1371 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1372 ModestMailOperationState *state;
1376 /* We can not just use the mail operation because the
1377 values of done and total could change before the
1379 state = modest_mail_operation_clone_state (info->mail_op);
1380 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1381 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1382 pair, (GDestroyNotify) modest_pair_free);
1384 g_object_unref (msg);
1385 g_object_unref (folder);
1392 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1395 /* Copy the headers to a list and free the array */
1396 new_headers = tny_simple_list_new ();
1397 for (i=0; i < new_headers_array->len; i++) {
1398 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1399 tny_list_append (new_headers, G_OBJECT (header));
1401 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1402 g_ptr_array_free (new_headers_array, FALSE);
1405 /* Perform send (if operation was not cancelled) */
1408 if (priv->account != NULL)
1409 g_object_unref (priv->account);
1411 if (info->transport_account) {
1412 priv->account = g_object_ref (info->transport_account);
1414 send_queue = modest_runtime_get_send_queue (info->transport_account);
1416 modest_tny_send_queue_try_to_send (send_queue);
1418 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1419 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1420 "cannot create a send queue for %s\n",
1421 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1422 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1426 /* Check if the operation was a success */
1428 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1430 /* Update the last updated key */
1431 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1432 set_last_updated_idle,
1433 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1434 (GDestroyNotify) g_free);
1438 /* Set the account back to not busy */
1439 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
1440 info->account_name, FALSE);
1442 if (info->callback) {
1443 UpdateAccountInfo *idle_info;
1445 /* This thread is not in the main lock */
1446 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1447 idle_info->mail_op = g_object_ref (info->mail_op);
1448 idle_info->new_headers = (new_headers) ? g_object_ref (new_headers) : NULL;
1449 idle_info->callback = info->callback;
1450 idle_info->user_data = info->user_data;
1451 g_idle_add (idle_update_account_cb, idle_info);
1454 /* Notify about operation end. Note that the info could be
1455 freed before this idle happens, but the mail operation will
1457 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1461 g_object_unref (new_headers);
1463 g_object_unref (all_folders);
1464 g_object_unref (info->account);
1465 if (info->transport_account)
1466 g_object_unref (info->transport_account);
1467 g_free (info->account_name);
1468 g_free (info->retrieve_type);
1469 g_slice_free (UpdateAccountInfo, info);
1477 modest_mail_operation_update_account (ModestMailOperation *self,
1478 const gchar *account_name,
1479 UpdateAccountCallback callback,
1482 GThread *thread = NULL;
1483 UpdateAccountInfo *info = NULL;
1484 ModestMailOperationPrivate *priv = NULL;
1485 ModestAccountMgr *mgr = NULL;
1486 TnyStoreAccount *store_account = NULL;
1487 TnyTransportAccount *transport_account = NULL;
1489 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1490 g_return_val_if_fail (account_name, FALSE);
1492 /* Init mail operation. Set total and done to 0, and do not
1493 update them, this way the progress objects will know that
1494 we have no clue about the number of the objects */
1495 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1498 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1499 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1501 /* Get the store account */
1502 store_account = (TnyStoreAccount *)
1503 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1505 TNY_ACCOUNT_TYPE_STORE);
1507 if (!store_account) {
1508 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1509 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1510 "cannot get tny store account for %s\n", account_name);
1514 priv->account = g_object_ref (store_account);
1516 /* Get the transport account, we can not do it in the thread
1517 due to some problems with dbus */
1518 transport_account = (TnyTransportAccount *)
1519 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1521 if (!transport_account) {
1522 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1523 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1524 "cannot get tny transport account for %s\n", account_name);
1528 /* Create the helper object */
1529 info = g_slice_new (UpdateAccountInfo);
1530 info->mail_op = self;
1531 info->account = store_account;
1532 info->transport_account = transport_account;
1533 info->callback = callback;
1534 info->account_name = g_strdup (account_name);
1535 info->user_data = user_data;
1537 /* Get the message size limit */
1538 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1539 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1540 if (info->max_size == 0)
1541 info->max_size = G_MAXINT;
1543 info->max_size = info->max_size * KB;
1545 /* Get per-account retrieval type */
1546 mgr = modest_runtime_get_account_mgr ();
1547 info->retrieve_type = modest_account_mgr_get_retrieve_type (mgr, account_name);
1549 /* Get per-account message amount retrieval limit */
1550 info->retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, account_name);
1551 if (info->retrieve_limit == 0)
1552 info->retrieve_limit = G_MAXINT;
1554 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1556 /* Set account busy */
1557 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1559 modest_mail_operation_notify_start (self);
1560 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1566 g_object_unref (store_account);
1567 if (transport_account)
1568 g_object_unref (transport_account);
1569 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1571 callback (self, NULL, user_data);
1573 modest_mail_operation_notify_end (self);
1577 /* ******************************************************************* */
1578 /* ************************** STORE ACTIONS ************************* */
1579 /* ******************************************************************* */
1583 modest_mail_operation_create_folder (ModestMailOperation *self,
1584 TnyFolderStore *parent,
1587 ModestMailOperationPrivate *priv;
1588 TnyFolder *new_folder = NULL;
1590 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1591 g_return_val_if_fail (name, NULL);
1593 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1594 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1595 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1596 g_object_ref (parent) :
1597 modest_tny_folder_get_account (TNY_FOLDER (parent));
1599 /* Check for already existing folder */
1600 if (modest_tny_folder_has_subfolder_with_name (parent, name)) {
1601 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1602 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1603 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1604 _CS("ckdg_ib_folder_already_exists"));
1608 if (TNY_IS_FOLDER (parent)) {
1609 /* Check folder rules */
1610 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1611 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1612 /* Set status failed and set an error */
1613 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1614 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1615 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1616 _("mail_in_ui_folder_create_error"));
1620 if (!strcmp (name, " ") || strchr (name, '/')) {
1621 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1622 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1623 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1624 _("mail_in_ui_folder_create_error"));
1628 /* Create the folder */
1629 modest_mail_operation_notify_start (self);
1630 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1631 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1633 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1636 /* Notify about operation end */
1637 modest_mail_operation_notify_end (self);
1643 modest_mail_operation_remove_folder (ModestMailOperation *self,
1645 gboolean remove_to_trash)
1647 TnyAccount *account;
1648 ModestMailOperationPrivate *priv;
1649 ModestTnyFolderRules rules;
1651 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1652 g_return_if_fail (TNY_IS_FOLDER (folder));
1654 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1656 /* Check folder rules */
1657 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1658 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1659 /* Set status failed and set an error */
1660 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1661 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1662 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1663 _("mail_in_ui_folder_delete_error"));
1667 /* Get the account */
1668 account = modest_tny_folder_get_account (folder);
1669 priv->account = g_object_ref(account);
1670 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1672 /* Delete folder or move to trash */
1673 if (remove_to_trash) {
1674 TnyFolder *trash_folder = NULL;
1675 trash_folder = modest_tny_account_get_special_folder (account,
1676 TNY_FOLDER_TYPE_TRASH);
1677 /* TODO: error_handling */
1679 modest_mail_operation_notify_start (self);
1680 modest_mail_operation_xfer_folder (self, folder,
1681 TNY_FOLDER_STORE (trash_folder),
1683 g_object_unref (trash_folder);
1686 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1688 modest_mail_operation_notify_start (self);
1689 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1690 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1693 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1696 g_object_unref (G_OBJECT (parent));
1698 g_object_unref (G_OBJECT (account));
1701 /* Notify about operation end */
1702 modest_mail_operation_notify_end (self);
1706 transfer_folder_status_cb (GObject *obj,
1710 ModestMailOperation *self;
1711 ModestMailOperationPrivate *priv;
1712 ModestMailOperationState *state;
1713 XFerMsgAsyncHelper *helper;
1715 g_return_if_fail (status != NULL);
1716 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1718 helper = (XFerMsgAsyncHelper *) user_data;
1719 g_return_if_fail (helper != NULL);
1721 self = helper->mail_op;
1722 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1724 priv->done = status->position;
1725 priv->total = status->of_total;
1727 state = modest_mail_operation_clone_state (self);
1729 /* This is not a GDK lock because we are a Tinymail callback
1730 * which is already GDK locked by Tinymail */
1732 /* no gdk_threads_enter (), CHECKED */
1734 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1736 /* no gdk_threads_leave (), CHECKED */
1738 g_slice_free (ModestMailOperationState, state);
1743 transfer_folder_cb (TnyFolder *folder,
1745 TnyFolderStore *into,
1746 TnyFolder *new_folder,
1750 XFerMsgAsyncHelper *helper;
1751 ModestMailOperation *self = NULL;
1752 ModestMailOperationPrivate *priv = NULL;
1754 helper = (XFerMsgAsyncHelper *) user_data;
1755 g_return_if_fail (helper != NULL);
1757 self = helper->mail_op;
1758 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1761 priv->error = g_error_copy (err);
1763 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1764 } else if (cancelled) {
1765 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1766 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1767 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1768 _("Transference of %s was cancelled."),
1769 tny_folder_get_name (folder));
1772 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1775 /* Notify about operation end */
1776 modest_mail_operation_notify_end (self);
1778 /* If user defined callback function was defined, call it */
1779 if (helper->user_callback) {
1781 /* This is not a GDK lock because we are a Tinymail callback
1782 * which is already GDK locked by Tinymail */
1784 /* no gdk_threads_enter (), CHECKED */
1785 helper->user_callback (self, helper->user_data);
1786 /* no gdk_threads_leave () , CHECKED */
1790 g_object_unref (helper->mail_op);
1791 g_slice_free (XFerMsgAsyncHelper, helper);
1796 * This function checks if the new name is a valid name for our local
1797 * folders account. The new name could not be the same than then name
1798 * of any of the mandatory local folders
1800 * We can not rely on tinymail because tinymail does not check the
1801 * name of the virtual folders that the account could have in the case
1802 * that we're doing a rename (because it directly calls Camel which
1803 * knows nothing about our virtual folders).
1805 * In the case of an actual copy/move (i.e. move/copy a folder between
1806 * accounts) tinymail uses the tny_folder_store_create_account which
1807 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1808 * checks the new name of the folder, so this call in that case
1809 * wouldn't be needed. *But* NOTE that if tinymail changes its
1810 * implementation (if folder transfers within the same account is no
1811 * longer implemented as a rename) this call will allow Modest to work
1814 * If the new name is not valid, this function will set the status to
1815 * failed and will set also an error in the mail operation
1818 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1819 TnyFolderStore *into,
1820 const gchar *new_name)
1822 if (TNY_IS_ACCOUNT (into) &&
1823 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1824 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1826 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1827 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1828 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1829 _("ckdg_ib_folder_already_exists"));
1836 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1838 TnyFolderStore *parent,
1839 gboolean delete_original,
1840 XferAsyncUserCallback user_callback,
1843 ModestMailOperationPrivate *priv = NULL;
1844 ModestTnyFolderRules parent_rules = 0, rules;
1845 XFerMsgAsyncHelper *helper = NULL;
1846 const gchar *folder_name = NULL;
1847 const gchar *error_msg;
1849 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1850 g_return_if_fail (TNY_IS_FOLDER (folder));
1851 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1853 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1854 folder_name = tny_folder_get_name (folder);
1856 /* Set the error msg */
1857 error_msg = _("mail_in_ui_folder_move_target_error");
1859 /* Get account and set it into mail_operation */
1860 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1861 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1862 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1864 /* Get folder rules */
1865 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1866 if (TNY_IS_FOLDER (parent))
1867 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1869 /* Apply operation constraints */
1870 if ((gpointer) parent == (gpointer) folder ||
1871 (!TNY_IS_FOLDER_STORE (parent)) ||
1872 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1875 } else if (TNY_IS_FOLDER (parent) &&
1876 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1880 } else if (TNY_IS_FOLDER (parent) &&
1881 TNY_IS_FOLDER_STORE (folder) &&
1882 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1883 TNY_FOLDER_STORE (folder))) {
1884 /* Do not move a parent into a child */
1886 } else if (TNY_IS_FOLDER_STORE (parent) &&
1887 modest_tny_folder_has_subfolder_with_name (parent, folder_name)) {
1888 /* Check that the new folder name is not used by any
1891 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1892 /* Check that the new folder name is not used by any
1893 special local folder */
1896 /* Create the helper */
1897 helper = g_slice_new0 (XFerMsgAsyncHelper);
1898 helper->mail_op = g_object_ref (self);
1899 helper->dest_folder = NULL;
1900 helper->headers = NULL;
1901 helper->user_callback = user_callback;
1902 helper->user_data = user_data;
1904 /* Move/Copy folder */
1905 modest_mail_operation_notify_start (self);
1906 tny_folder_copy_async (folder,
1908 tny_folder_get_name (folder),
1911 transfer_folder_status_cb,
1917 /* Set status failed and set an error */
1918 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1919 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1920 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1923 /* Call the user callback if exists */
1925 user_callback (self, user_data);
1927 /* Notify the queue */
1928 modest_mail_operation_notify_end (self);
1932 modest_mail_operation_rename_folder (ModestMailOperation *self,
1936 ModestMailOperationPrivate *priv;
1937 ModestTnyFolderRules rules;
1938 XFerMsgAsyncHelper *helper;
1940 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1941 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1942 g_return_if_fail (name);
1944 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1946 /* Get account and set it into mail_operation */
1947 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1948 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1950 /* Check folder rules */
1951 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1952 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1953 /* Set status failed and set an error */
1954 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1955 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1956 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1957 _("FIXME: unable to rename"));
1959 /* Notify about operation end */
1960 modest_mail_operation_notify_end (self);
1961 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1962 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1963 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1964 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1965 _("FIXME: unable to rename"));
1966 /* Notify about operation end */
1967 modest_mail_operation_notify_end (self);
1969 TnyFolderStore *into;
1971 into = tny_folder_get_folder_store (folder);
1973 /* Check that the new folder name is not used by any
1974 special local folder */
1975 if (new_name_valid_if_local_account (priv, into, name)) {
1976 /* Create the helper */
1977 helper = g_slice_new0 (XFerMsgAsyncHelper);
1978 helper->mail_op = g_object_ref(self);
1979 helper->dest_folder = NULL;
1980 helper->headers = NULL;
1981 helper->user_callback = NULL;
1982 helper->user_data = NULL;
1984 /* Rename. Camel handles folder subscription/unsubscription */
1985 modest_mail_operation_notify_start (self);
1986 tny_folder_copy_async (folder, into, name, TRUE,
1988 transfer_folder_status_cb,
1991 modest_mail_operation_notify_end (self);
1993 g_object_unref (into);
1997 /* ******************************************************************* */
1998 /* ************************** MSG ACTIONS ************************* */
1999 /* ******************************************************************* */
2002 modest_mail_operation_get_msg (ModestMailOperation *self,
2004 GetMsgAsyncUserCallback user_callback,
2007 GetMsgAsyncHelper *helper = NULL;
2009 ModestMailOperationPrivate *priv;
2011 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2012 g_return_if_fail (TNY_IS_HEADER (header));
2014 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2015 folder = tny_header_get_folder (header);
2017 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2018 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2020 /* Get account and set it into mail_operation */
2021 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2023 /* Check for cached messages */
2024 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2025 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2027 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2029 helper = g_slice_new0 (GetMsgAsyncHelper);
2030 helper->mail_op = self;
2031 helper->user_callback = user_callback;
2032 helper->user_data = user_data;
2033 helper->header = g_object_ref (header);
2035 /* The callback's reference so that the mail op is not
2036 * finalized until the async operation is completed even if
2037 * the user canceled the request meanwhile.
2039 g_object_ref (G_OBJECT (helper->mail_op));
2041 modest_mail_operation_notify_start (self);
2042 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
2044 g_object_unref (G_OBJECT (folder));
2048 get_msg_cb (TnyFolder *folder,
2054 GetMsgAsyncHelper *helper = NULL;
2055 ModestMailOperation *self = NULL;
2056 ModestMailOperationPrivate *priv = NULL;
2058 helper = (GetMsgAsyncHelper *) user_data;
2059 g_return_if_fail (helper != NULL);
2060 self = helper->mail_op;
2061 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2062 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2064 /* Check errors and cancel */
2066 priv->error = g_error_copy (error);
2067 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2068 } else if (cancelled) {
2069 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2070 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2071 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2072 _("Error trying to refresh the contents of %s"),
2073 tny_folder_get_name (folder));
2075 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2078 /* If user defined callback function was defined, call it even
2079 if the operation failed*/
2080 if (helper->user_callback) {
2081 /* This is not a GDK lock because we are a Tinymail callback
2082 * which is already GDK locked by Tinymail */
2084 /* no gdk_threads_enter (), CHECKED */
2085 helper->user_callback (self, helper->header, msg, helper->user_data);
2086 /* no gdk_threads_leave (), CHECKED */
2089 /* Notify about operation end */
2090 modest_mail_operation_notify_end (self);
2092 g_object_unref (helper->mail_op);
2093 g_object_unref (helper->header);
2094 g_slice_free (GetMsgAsyncHelper, helper);
2099 get_msg_status_cb (GObject *obj,
2103 GetMsgAsyncHelper *helper = NULL;
2104 ModestMailOperation *self;
2105 ModestMailOperationPrivate *priv;
2106 ModestMailOperationState *state;
2108 g_return_if_fail (status != NULL);
2109 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2111 helper = (GetMsgAsyncHelper *) user_data;
2112 g_return_if_fail (helper != NULL);
2114 self = helper->mail_op;
2115 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2120 state = modest_mail_operation_clone_state (self);
2121 state->bytes_done = status->position;
2122 state->bytes_total = status->of_total;
2124 /* This is not a GDK lock because we are a Tinymail callback
2125 * which is already GDK locked by Tinymail */
2127 /* no gdk_threads_enter (), CHECKED */
2128 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2129 /* no gdk_threads_leave (), CHECKED */
2131 g_slice_free (ModestMailOperationState, state);
2134 /****************************************************/
2136 ModestMailOperation *mail_op;
2138 GetMsgAsyncUserCallback user_callback;
2140 GDestroyNotify notify;
2144 GetMsgAsyncUserCallback user_callback;
2148 ModestMailOperation *mail_op;
2149 } NotifyGetMsgsInfo;
2153 * Used by get_msgs_full_thread to call the user_callback for each
2154 * message that has been read
2157 notify_get_msgs_full (gpointer data)
2159 NotifyGetMsgsInfo *info;
2161 info = (NotifyGetMsgsInfo *) data;
2163 /* This is a GDK lock because we are an idle callback and
2164 * because info->user_callback can contain Gtk+ code */
2166 gdk_threads_enter (); /* CHECKED */
2167 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2168 gdk_threads_leave (); /* CHECKED */
2170 g_slice_free (NotifyGetMsgsInfo, info);
2176 * Used by get_msgs_full_thread to free al the thread resources and to
2177 * call the destroy function for the passed user_data
2180 get_msgs_full_destroyer (gpointer data)
2182 GetFullMsgsInfo *info;
2184 info = (GetFullMsgsInfo *) data;
2188 /* This is a GDK lock because we are an idle callback and
2189 * because info->notify can contain Gtk+ code */
2191 gdk_threads_enter (); /* CHECKED */
2192 info->notify (info->user_data);
2193 gdk_threads_leave (); /* CHECKED */
2197 g_object_unref (info->headers);
2198 g_slice_free (GetFullMsgsInfo, info);
2204 get_msgs_full_thread (gpointer thr_user_data)
2206 GetFullMsgsInfo *info;
2207 ModestMailOperationPrivate *priv = NULL;
2208 TnyIterator *iter = NULL;
2210 info = (GetFullMsgsInfo *) thr_user_data;
2211 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2213 iter = tny_list_create_iterator (info->headers);
2214 while (!tny_iterator_is_done (iter)) {
2218 header = TNY_HEADER (tny_iterator_get_current (iter));
2219 folder = tny_header_get_folder (header);
2221 /* Check for cached messages */
2222 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2223 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2225 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2227 /* Get message from folder */
2230 /* The callback will call it per each header */
2231 msg = tny_folder_get_msg (folder, header, &(priv->error));
2234 ModestMailOperationState *state;
2239 /* notify progress */
2240 state = modest_mail_operation_clone_state (info->mail_op);
2241 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2242 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2243 pair, (GDestroyNotify) modest_pair_free);
2245 /* The callback is the responsible for
2246 freeing the message */
2247 if (info->user_callback) {
2248 NotifyGetMsgsInfo *info_notify;
2249 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2250 info_notify->user_callback = info->user_callback;
2251 info_notify->mail_op = info->mail_op;
2252 info_notify->header = g_object_ref (header);
2253 info_notify->msg = g_object_ref (msg);
2254 info_notify->user_data = info->user_data;
2255 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2256 notify_get_msgs_full,
2259 g_object_unref (msg);
2262 /* Set status failed and set an error */
2263 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2264 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2265 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2266 "Error trying to get a message. No folder found for header");
2270 g_object_unref (header);
2272 tny_iterator_next (iter);
2275 /* Set operation status */
2276 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2277 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2279 /* Notify about operation end */
2280 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2282 /* Free thread resources. Will be called after all previous idles */
2283 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2289 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2290 TnyList *header_list,
2291 GetMsgAsyncUserCallback user_callback,
2293 GDestroyNotify notify)
2295 TnyHeader *header = NULL;
2296 TnyFolder *folder = NULL;
2298 ModestMailOperationPrivate *priv = NULL;
2299 GetFullMsgsInfo *info = NULL;
2300 gboolean size_ok = TRUE;
2302 TnyIterator *iter = NULL;
2304 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2306 /* Init mail operation */
2307 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2308 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2309 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2311 priv->total = tny_list_get_length(header_list);
2313 /* Get account and set it into mail_operation */
2314 if (tny_list_get_length (header_list) >= 1) {
2315 iter = tny_list_create_iterator (header_list);
2316 header = TNY_HEADER (tny_iterator_get_current (iter));
2318 folder = tny_header_get_folder (header);
2320 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2321 g_object_unref (folder);
2323 g_object_unref (header);
2326 if (tny_list_get_length (header_list) == 1) {
2327 g_object_unref (iter);
2332 /* Get msg size limit */
2333 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2334 MODEST_CONF_MSG_SIZE_LIMIT,
2337 g_clear_error (&(priv->error));
2338 max_size = G_MAXINT;
2340 max_size = max_size * KB;
2343 /* Check message size limits. If there is only one message
2344 always retrieve it */
2346 while (!tny_iterator_is_done (iter) && size_ok) {
2347 header = TNY_HEADER (tny_iterator_get_current (iter));
2349 if (tny_header_get_message_size (header) >= max_size)
2351 g_object_unref (header);
2354 tny_iterator_next (iter);
2356 g_object_unref (iter);
2360 /* Create the info */
2361 info = g_slice_new0 (GetFullMsgsInfo);
2362 info->mail_op = self;
2363 info->user_callback = user_callback;
2364 info->user_data = user_data;
2365 info->headers = g_object_ref (header_list);
2366 info->notify = notify;
2368 modest_mail_operation_notify_start (self);
2369 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2371 /* Set status failed and set an error */
2372 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2373 /* FIXME: the error msg is different for pop */
2374 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2375 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2376 _("emev_ni_ui_imap_msg_size_exceed_error"));
2377 /* Remove from queue and free resources */
2378 modest_mail_operation_notify_end (self);
2386 modest_mail_operation_remove_msg (ModestMailOperation *self,
2388 gboolean remove_to_trash /*ignored*/)
2391 ModestMailOperationPrivate *priv;
2393 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2394 g_return_if_fail (TNY_IS_HEADER (header));
2396 if (remove_to_trash)
2397 g_warning ("remove to trash is not implemented");
2399 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2400 folder = tny_header_get_folder (header);
2402 /* Get account and set it into mail_operation */
2403 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2404 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2405 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2407 /* remove message from folder */
2408 tny_folder_remove_msg (folder, header, &(priv->error));
2410 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2411 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2413 modest_mail_operation_notify_start (self);
2415 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2416 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* FALSE --> don't expunge *\/ */
2417 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2418 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2419 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* TRUE --> dont expunge *\/ */
2420 tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2423 /* tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /\* TRUE --> expunge *\/ */
2424 tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2430 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2432 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2435 g_object_unref (G_OBJECT (folder));
2437 /* Notify about operation end */
2438 modest_mail_operation_notify_end (self);
2442 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2444 gboolean remove_to_trash /*ignored*/)
2447 ModestMailOperationPrivate *priv;
2448 TnyIterator *iter = NULL;
2449 TnyHeader *header = NULL;
2451 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2452 g_return_if_fail (TNY_IS_LIST (headers));
2454 if (remove_to_trash)
2455 g_warning ("remove to trash is not implemented");
2457 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2459 /* Get folder from first header and sync it */
2460 iter = tny_list_create_iterator (headers);
2461 header = TNY_HEADER (tny_iterator_get_current (iter));
2462 folder = tny_header_get_folder (header);
2464 /* Get account and set it into mail_operation */
2465 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2466 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2467 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2469 /* remove message from folder */
2470 modest_mail_operation_notify_start (self);
2472 tny_folder_remove_msgs (folder, headers, &(priv->error));
2474 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2475 TNY_IS_CAMEL_POP_FOLDER (folder))
2476 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> don't expunge */
2479 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2485 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2487 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2490 g_object_unref (header);
2491 g_object_unref (iter);
2492 g_object_unref (G_OBJECT (folder));
2494 /* Notify about operation end */
2495 modest_mail_operation_notify_end (self);
2500 transfer_msgs_status_cb (GObject *obj,
2504 XFerMsgAsyncHelper *helper = NULL;
2505 ModestMailOperation *self;
2506 ModestMailOperationPrivate *priv;
2507 ModestMailOperationState *state;
2510 g_return_if_fail (status != NULL);
2511 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2513 helper = (XFerMsgAsyncHelper *) user_data;
2514 g_return_if_fail (helper != NULL);
2516 self = helper->mail_op;
2517 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2519 priv->done = status->position;
2520 priv->total = status->of_total;
2522 state = modest_mail_operation_clone_state (self);
2524 /* This is not a GDK lock because we are a Tinymail callback and
2525 * Tinymail already acquires the Gdk lock */
2527 /* no gdk_threads_enter (), CHECKED */
2529 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2531 /* no gdk_threads_leave (), CHECKED */
2533 g_slice_free (ModestMailOperationState, state);
2538 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2540 XFerMsgAsyncHelper *helper;
2541 ModestMailOperation *self;
2542 ModestMailOperationPrivate *priv;
2543 TnyIterator *iter = NULL;
2544 TnyHeader *header = NULL;
2546 helper = (XFerMsgAsyncHelper *) user_data;
2547 self = helper->mail_op;
2549 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2552 priv->error = g_error_copy (err);
2554 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2555 } else if (cancelled) {
2556 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2557 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2558 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2559 _("Error trying to refresh the contents of %s"),
2560 tny_folder_get_name (folder));
2563 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2565 /* Update folder counts */
2566 tny_folder_poke_status (folder);
2567 tny_folder_poke_status (helper->dest_folder);
2571 /* Mark headers as deleted and seen */
2572 if ((helper->delete) &&
2573 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2574 iter = tny_list_create_iterator (helper->headers);
2575 while (!tny_iterator_is_done (iter)) {
2576 header = TNY_HEADER (tny_iterator_get_current (iter));
2577 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2578 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2579 g_object_unref (header);
2581 tny_iterator_next (iter);
2587 /* Notify about operation end */
2588 modest_mail_operation_notify_end (self);
2590 /* If user defined callback function was defined, call it */
2591 if (helper->user_callback) {
2592 /* This is not a GDK lock because we are a Tinymail callback and
2593 * Tinymail already acquires the Gdk lock */
2595 /* no gdk_threads_enter (), CHECKED */
2596 helper->user_callback (self, helper->user_data);
2597 /* no gdk_threads_leave (), CHECKED */
2601 if (helper->headers)
2602 g_object_unref (helper->headers);
2603 if (helper->dest_folder)
2604 g_object_unref (helper->dest_folder);
2605 if (helper->mail_op)
2606 g_object_unref (helper->mail_op);
2608 g_object_unref (folder);
2610 g_object_unref (iter);
2611 g_slice_free (XFerMsgAsyncHelper, helper);
2615 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2618 gboolean delete_original,
2619 XferAsyncUserCallback user_callback,
2622 ModestMailOperationPrivate *priv = NULL;
2623 TnyIterator *iter = NULL;
2624 TnyFolder *src_folder = NULL;
2625 XFerMsgAsyncHelper *helper = NULL;
2626 TnyHeader *header = NULL;
2627 ModestTnyFolderRules rules = 0;
2629 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2630 g_return_if_fail (TNY_IS_LIST (headers));
2631 g_return_if_fail (TNY_IS_FOLDER (folder));
2633 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2636 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2637 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2639 /* Apply folder rules */
2640 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2641 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2642 /* Set status failed and set an error */
2643 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2644 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2645 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2646 _CS("ckct_ib_unable_to_paste_here"));
2647 /* Notify the queue */
2648 modest_mail_operation_notify_end (self);
2652 /* Get source folder */
2653 iter = tny_list_create_iterator (headers);
2654 header = TNY_HEADER (tny_iterator_get_current (iter));
2656 src_folder = tny_header_get_folder (header);
2657 g_object_unref (header);
2660 g_object_unref (iter);
2662 /* Check folder source and destination */
2663 if (src_folder == folder) {
2664 /* Set status failed and set an error */
2665 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2666 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2667 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2668 _("mcen_ib_unable_to_copy_samefolder"));
2670 /* Notify the queue */
2671 modest_mail_operation_notify_end (self);
2674 g_object_unref (src_folder);
2678 /* Create the helper */
2679 helper = g_slice_new0 (XFerMsgAsyncHelper);
2680 helper->mail_op = g_object_ref(self);
2681 helper->dest_folder = g_object_ref(folder);
2682 helper->headers = g_object_ref(headers);
2683 helper->user_callback = user_callback;
2684 helper->user_data = user_data;
2685 helper->delete = delete_original;
2687 /* Get account and set it into mail_operation */
2688 priv->account = modest_tny_folder_get_account (src_folder);
2690 /* Transfer messages */
2691 modest_mail_operation_notify_start (self);
2692 tny_folder_transfer_msgs_async (src_folder,
2697 transfer_msgs_status_cb,
2703 on_refresh_folder (TnyFolder *folder,
2708 RefreshAsyncHelper *helper = NULL;
2709 ModestMailOperation *self = NULL;
2710 ModestMailOperationPrivate *priv = NULL;
2712 helper = (RefreshAsyncHelper *) user_data;
2713 self = helper->mail_op;
2714 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2716 g_return_if_fail(priv!=NULL);
2719 priv->error = g_error_copy (error);
2720 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2725 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2726 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2727 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2728 _("Error trying to refresh the contents of %s"),
2729 tny_folder_get_name (folder));
2733 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2736 /* Call user defined callback, if it exists */
2737 if (helper->user_callback) {
2739 /* This is not a GDK lock because we are a Tinymail callback and
2740 * Tinymail already acquires the Gdk lock */
2741 helper->user_callback (self, folder, helper->user_data);
2745 g_slice_free (RefreshAsyncHelper, helper);
2747 /* Notify about operation end */
2748 modest_mail_operation_notify_end (self);
2749 g_object_unref(self);
2753 on_refresh_folder_status_update (GObject *obj,
2757 RefreshAsyncHelper *helper = NULL;
2758 ModestMailOperation *self = NULL;
2759 ModestMailOperationPrivate *priv = NULL;
2760 ModestMailOperationState *state;
2762 g_return_if_fail (user_data != NULL);
2763 g_return_if_fail (status != NULL);
2764 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2766 helper = (RefreshAsyncHelper *) user_data;
2767 self = helper->mail_op;
2768 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2770 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2772 priv->done = status->position;
2773 priv->total = status->of_total;
2775 state = modest_mail_operation_clone_state (self);
2777 /* This is not a GDK lock because we are a Tinymail callback and
2778 * Tinymail already acquires the Gdk lock */
2779 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2781 g_slice_free (ModestMailOperationState, state);
2785 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2787 RefreshAsyncUserCallback user_callback,
2790 ModestMailOperationPrivate *priv = NULL;
2791 RefreshAsyncHelper *helper = NULL;
2793 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2795 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2797 /* Get account and set it into mail_operation */
2798 priv->account = modest_tny_folder_get_account (folder);
2799 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2801 /* Create the helper */
2802 helper = g_slice_new0 (RefreshAsyncHelper);
2803 helper->mail_op = g_object_ref(self);
2804 helper->user_callback = user_callback;
2805 helper->user_data = user_data;
2807 /* Refresh the folder. TODO: tinymail could issue a status
2808 updates before the callback call then this could happen. We
2809 must review the design */
2810 modest_mail_operation_notify_start (self);
2811 tny_folder_refresh_async (folder,
2813 on_refresh_folder_status_update,
2819 modest_mail_operation_notify_start (ModestMailOperation *self)
2821 ModestMailOperationPrivate *priv = NULL;
2823 g_return_if_fail (self);
2825 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2827 /* Ensure that all the fields are filled correctly */
2828 g_return_if_fail (priv->account != NULL);
2829 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
2831 /* Notify the observers about the mail operation. We do not
2832 wrapp this emission because we assume that this function is
2833 always called from within the main lock */
2834 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
2839 * It's used by the mail operation queue to notify the observers
2840 * attached to that signal that the operation finished. We need to use
2841 * that because tinymail does not give us the progress of a given
2842 * operation when it finishes (it directly calls the operation
2846 modest_mail_operation_notify_end (ModestMailOperation *self)
2848 ModestMailOperationPrivate *priv = NULL;
2850 g_return_if_fail (self);
2852 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2854 /* Notify the observers about the mail operation end. We do
2855 not wrapp this emission because we assume that this
2856 function is always called from within the main lock */
2857 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
2859 /* Remove the error user data */
2860 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
2861 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
2865 modest_mail_operation_get_account (ModestMailOperation *self)
2867 ModestMailOperationPrivate *priv = NULL;
2869 g_return_val_if_fail (self, NULL);
2871 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2873 return (priv->account) ? g_object_ref (priv->account) : NULL;