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 {
103 ErrorCheckingUserCallback error_checking;
104 gpointer error_checking_user_data;
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 (ModestMailOperationTypeOperation op_type,
320 ModestMailOperation *obj;
321 ModestMailOperationPrivate *priv;
323 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
324 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
326 priv->op_type = op_type;
328 priv->source = g_object_ref(source);
334 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
336 ErrorCheckingUserCallback error_handler,
339 ModestMailOperation *obj;
340 ModestMailOperationPrivate *priv;
342 obj = modest_mail_operation_new (op_type, source);
343 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
345 g_return_val_if_fail (error_handler != NULL, obj);
346 priv->error_checking = error_handler;
347 priv->error_checking_user_data = user_data;
353 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
355 ModestMailOperationPrivate *priv;
357 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
358 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
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 = info->mail_op;
676 g_object_ref (info->mail_op);
677 idle_info->msg = new_msg;
679 g_object_ref (new_msg);
680 idle_info->callback = info->callback;
681 idle_info->userdata = info->userdata;
682 g_idle_add (idle_create_msg_cb, idle_info);
684 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
687 g_object_unref (info->mail_op);
688 g_slice_free (CreateMsgInfo, info);
693 modest_mail_operation_create_msg (ModestMailOperation *self,
694 const gchar *from, const gchar *to,
695 const gchar *cc, const gchar *bcc,
696 const gchar *subject, const gchar *plain_body,
697 const gchar *html_body,
698 const GList *attachments_list,
699 const GList *images_list,
700 TnyHeaderFlags priority_flags,
701 ModestMailOperationCreateMsgCallback callback,
704 CreateMsgInfo *info = NULL;
706 info = g_slice_new0 (CreateMsgInfo);
707 info->mail_op = self;
710 info->from = g_strdup (from);
711 info->to = g_strdup (to);
712 info->cc = g_strdup (cc);
713 info->bcc = g_strdup (bcc);
714 info->subject = g_strdup (subject);
715 info->plain_body = g_strdup (plain_body);
716 info->html_body = g_strdup (html_body);
717 info->attachments_list = g_list_copy ((GList *) attachments_list);
718 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
719 info->images_list = g_list_copy ((GList *) images_list);
720 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
721 info->priority_flags = priority_flags;
723 info->callback = callback;
724 info->userdata = userdata;
726 g_thread_create (create_msg_thread, info, FALSE, NULL);
731 TnyTransportAccount *transport_account;
736 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
740 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
741 TnyFolder *draft_folder = NULL;
742 TnyFolder *outbox_folder = NULL;
750 /* Call mail operation */
751 modest_mail_operation_send_mail (self, info->transport_account, msg);
753 /* Remove old mail from its source folder */
754 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
755 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_OUTBOX);
756 if (info->draft_msg != NULL) {
757 TnyFolder *folder = NULL;
758 TnyFolder *src_folder = NULL;
759 TnyFolderType folder_type;
760 folder = tny_msg_get_folder (info->draft_msg);
761 if (folder == NULL) goto end;
762 folder_type = modest_tny_folder_guess_folder_type (folder);
763 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
764 src_folder = outbox_folder;
766 src_folder = draft_folder;
768 /* Note: This can fail (with a warning) if the message is not really already in a folder,
769 * because this function requires it to have a UID. */
770 header = tny_msg_get_header (info->draft_msg);
771 tny_folder_remove_msg (src_folder, header, NULL);
773 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
774 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
776 g_object_unref (header);
777 g_object_unref (folder);
784 g_object_unref (info->draft_msg);
786 g_object_unref (draft_folder);
788 g_object_unref (outbox_folder);
789 if (info->transport_account)
790 g_object_unref (info->transport_account);
791 g_slice_free (SendNewMailInfo, info);
792 modest_mail_operation_notify_end (self);
796 modest_mail_operation_send_new_mail (ModestMailOperation *self,
797 TnyTransportAccount *transport_account,
799 const gchar *from, const gchar *to,
800 const gchar *cc, const gchar *bcc,
801 const gchar *subject, const gchar *plain_body,
802 const gchar *html_body,
803 const GList *attachments_list,
804 const GList *images_list,
805 TnyHeaderFlags priority_flags)
807 ModestMailOperationPrivate *priv = NULL;
808 SendNewMailInfo *info;
810 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
811 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
813 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
815 /* Check parametters */
817 /* Set status failed and set an error */
818 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
819 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
820 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
821 _("Error trying to send a mail. You need to set at least one recipient"));
824 info = g_slice_new0 (SendNewMailInfo);
825 info->transport_account = transport_account;
826 if (transport_account)
827 g_object_ref (transport_account);
828 info->draft_msg = draft_msg;
830 g_object_ref (draft_msg);
833 modest_mail_operation_notify_start (self);
834 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
835 attachments_list, images_list, priority_flags,
836 modest_mail_operation_send_new_mail_cb, info);
842 TnyTransportAccount *transport_account;
844 ModestMsgEditWindow *edit_window;
848 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
852 TnyFolder *src_folder = NULL;
853 TnyFolder *drafts = NULL;
854 TnyHeader *header = NULL;
855 ModestMailOperationPrivate *priv = NULL;
856 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
858 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;
899 if (info->edit_window)
900 modest_msg_edit_window_set_draft (info->edit_window, msg);
905 g_object_unref (G_OBJECT(drafts));
907 g_object_unref (G_OBJECT(src_folder));
908 if (info->edit_window)
909 g_object_unref (G_OBJECT(info->edit_window));
911 g_object_unref (G_OBJECT (info->draft_msg));
912 if (info->transport_account)
913 g_object_unref (G_OBJECT(info->transport_account));
914 g_slice_free (SaveToDraftsInfo, info);
916 modest_mail_operation_notify_end (self);
920 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
921 TnyTransportAccount *transport_account,
923 ModestMsgEditWindow *edit_window,
924 const gchar *from, const gchar *to,
925 const gchar *cc, const gchar *bcc,
926 const gchar *subject, const gchar *plain_body,
927 const gchar *html_body,
928 const GList *attachments_list,
929 const GList *images_list,
930 TnyHeaderFlags priority_flags)
932 ModestMailOperationPrivate *priv = NULL;
933 SaveToDraftsInfo *info = NULL;
935 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
936 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
938 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
940 /* Get account and set it into mail_operation */
941 priv->account = g_object_ref (transport_account);
943 info = g_slice_new0 (SaveToDraftsInfo);
944 info->transport_account = g_object_ref (transport_account);
945 info->draft_msg = draft_msg;
947 g_object_ref (draft_msg);
948 info->edit_window = edit_window;
950 g_object_ref (edit_window);
952 modest_mail_operation_notify_start (self);
953 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
954 attachments_list, images_list, priority_flags,
955 modest_mail_operation_save_to_drafts_cb, info);
960 ModestMailOperation *mail_op;
961 TnyStoreAccount *account;
962 TnyTransportAccount *transport_account;
965 gchar *retrieve_type;
967 UpdateAccountCallback callback;
969 TnyList *new_headers;
974 ModestMailOperation *mail_op;
975 TnyMimePart *mime_part;
977 GetMimePartSizeCallback callback;
979 } GetMimePartSizeInfo;
981 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
982 /* We use this folder observer to track the headers that have been
983 * added to a folder */
986 TnyList *new_headers;
987 } InternalFolderObserver;
991 } InternalFolderObserverClass;
993 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
995 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
996 internal_folder_observer,
998 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1002 foreach_add_item (gpointer header, gpointer user_data)
1004 tny_list_prepend (TNY_LIST (user_data),
1005 g_object_ref (G_OBJECT (header)));
1008 /* This is the method that looks for new messages in a folder */
1010 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1012 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1014 TnyFolderChangeChanged changed;
1016 changed = tny_folder_change_get_changed (change);
1018 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1021 /* Get added headers */
1022 list = tny_simple_list_new ();
1023 tny_folder_change_get_added_headers (change, list);
1025 /* Add them to the folder observer */
1026 tny_list_foreach (list, foreach_add_item,
1027 derived->new_headers);
1029 g_object_unref (G_OBJECT (list));
1034 internal_folder_observer_init (InternalFolderObserver *self)
1036 self->new_headers = tny_simple_list_new ();
1039 internal_folder_observer_finalize (GObject *object)
1041 InternalFolderObserver *self;
1043 self = (InternalFolderObserver *) object;
1044 g_object_unref (self->new_headers);
1046 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1049 tny_folder_observer_init (TnyFolderObserverIface *iface)
1051 iface->update_func = internal_folder_observer_update;
1054 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1056 GObjectClass *object_class;
1058 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1059 object_class = (GObjectClass*) klass;
1060 object_class->finalize = internal_folder_observer_finalize;
1066 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
1069 TnyList *folders = tny_simple_list_new ();
1071 tny_folder_store_get_folders (store, folders, query, NULL);
1072 iter = tny_list_create_iterator (folders);
1074 while (!tny_iterator_is_done (iter)) {
1076 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1078 tny_list_prepend (all_folders, G_OBJECT (folder));
1079 recurse_folders (folder, query, all_folders);
1080 g_object_unref (G_OBJECT (folder));
1083 tny_iterator_next (iter);
1085 g_object_unref (G_OBJECT (iter));
1086 g_object_unref (G_OBJECT (folders));
1090 * Issues the "progress-changed" signal. The timer won't be removed,
1091 * so you must call g_source_remove to stop the signal emission
1094 idle_notify_progress (gpointer data)
1096 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1097 ModestMailOperationState *state;
1099 state = modest_mail_operation_clone_state (mail_op);
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 (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1106 gdk_threads_leave (); /* CHECKED */
1108 g_slice_free (ModestMailOperationState, state);
1114 * Issues the "progress-changed" signal and removes the timer. It uses
1115 * a lock to ensure that the progress information of the mail
1116 * operation is not modified while there are notifications pending
1119 idle_notify_progress_once (gpointer data)
1123 pair = (ModestPair *) data;
1125 /* This is a GDK lock because we are an idle callback and
1126 * the handlers of this signal can contain Gtk+ code */
1128 gdk_threads_enter (); /* CHECKED */
1129 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1130 gdk_threads_leave (); /* CHECKED */
1132 /* Free the state and the reference to the mail operation */
1133 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1134 g_object_unref (pair->first);
1140 * Used to notify the queue from the main
1141 * loop. We call it inside an idle call to achieve that
1144 idle_notify_queue (gpointer data)
1146 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1148 /* Do not need to block, the notify end will do it for us */
1149 modest_mail_operation_notify_end (mail_op);
1150 g_object_unref (mail_op);
1156 compare_headers_by_date (gconstpointer a,
1159 TnyHeader **header1, **header2;
1160 time_t sent1, sent2;
1162 header1 = (TnyHeader **) a;
1163 header2 = (TnyHeader **) b;
1165 sent1 = tny_header_get_date_sent (*header1);
1166 sent2 = tny_header_get_date_sent (*header2);
1168 /* We want the most recent ones (greater time_t) at the
1177 set_last_updated_idle (gpointer data)
1180 /* This is a GDK lock because we are an idle callback and
1181 * modest_account_mgr_set_last_updated can issue Gtk+ code */
1183 gdk_threads_enter (); /* CHECKED - please recheck */
1185 /* It does not matter if the time is not exactly the same than
1186 the time when this idle was called, it's just an
1187 approximation and it won't be very different */
1189 modest_account_mgr_set_last_updated (modest_runtime_get_account_mgr (),
1193 gdk_threads_leave (); /* CHECKED - please recheck */
1199 idle_update_account_cb (gpointer data)
1201 UpdateAccountInfo *idle_info;
1203 idle_info = (UpdateAccountInfo *) data;
1205 /* This is a GDK lock because we are an idle callback and
1206 * idle_info->callback can contain Gtk+ code */
1208 gdk_threads_enter (); /* CHECKED */
1209 idle_info->callback (idle_info->mail_op,
1210 idle_info->new_headers,
1211 idle_info->user_data);
1212 gdk_threads_leave (); /* CHECKED */
1215 g_object_unref (idle_info->mail_op);
1216 if (idle_info->new_headers)
1217 g_object_unref (idle_info->new_headers);
1224 get_all_folders_from_account (TnyStoreAccount *account,
1227 TnyList *all_folders = NULL;
1228 TnyIterator *iter = NULL;
1229 TnyFolderStoreQuery *query = NULL;
1231 all_folders = tny_simple_list_new ();
1232 query = tny_folder_store_query_new ();
1233 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1234 tny_folder_store_get_folders (TNY_FOLDER_STORE (account),
1241 g_object_unref (all_folders);
1245 iter = tny_list_create_iterator (all_folders);
1246 while (!tny_iterator_is_done (iter)) {
1247 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1249 recurse_folders (folder, query, all_folders);
1250 g_object_unref (folder);
1252 tny_iterator_next (iter);
1254 g_object_unref (G_OBJECT (iter));
1261 update_account_thread (gpointer thr_user_data)
1263 static gboolean first_time = TRUE;
1264 UpdateAccountInfo *info = NULL;
1265 TnyList *all_folders = NULL, *new_headers = NULL;
1266 GPtrArray *new_headers_array = NULL;
1267 TnyIterator *iter = NULL;
1268 ModestMailOperationPrivate *priv = NULL;
1269 ModestTnySendQueue *send_queue = NULL;
1270 gint i = 0, timeout = 0;
1272 info = (UpdateAccountInfo *) thr_user_data;
1273 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1275 /* Get account and set it into mail_operation */
1276 priv->account = g_object_ref (info->account);
1278 /* Get all the folders. We can do it synchronously because
1279 we're already running in a different thread than the UI */
1280 all_folders = get_all_folders_from_account (info->account, &(priv->error));
1282 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1286 /* Update status and notify. We need to call the notification
1287 with a source function in order to call it from the main
1288 loop. We need that in order not to get into trouble with
1289 Gtk+. We use a timeout in order to provide more status
1290 information, because the sync tinymail call does not
1291 provide it for the moment */
1292 timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1294 new_headers_array = g_ptr_array_new ();
1295 iter = tny_list_create_iterator (all_folders);
1297 while (!tny_iterator_is_done (iter) && !priv->error &&
1298 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1300 TnyFolderType folder_type;
1301 TnyFolder *folder = NULL;
1303 folder = TNY_FOLDER (tny_iterator_get_current (iter));
1304 folder_type = tny_folder_get_folder_type (folder);
1306 /* Refresh it only if it's the INBOX */
1307 if (folder_type == TNY_FOLDER_TYPE_INBOX) {
1308 InternalFolderObserver *observer = NULL;
1309 TnyIterator *new_headers_iter = NULL;
1311 /* Refresh the folder. Our observer receives
1312 * the new emails during folder refreshes, so
1313 * we can use observer->new_headers
1315 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1316 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1318 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1320 new_headers_iter = tny_list_create_iterator (observer->new_headers);
1321 while (!tny_iterator_is_done (new_headers_iter)) {
1322 TnyHeader *header = NULL;
1324 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1325 /* Apply per-message size limits */
1326 if (tny_header_get_message_size (header) < info->max_size)
1327 g_ptr_array_add (new_headers_array, g_object_ref (header));
1329 g_object_unref (header);
1330 tny_iterator_next (new_headers_iter);
1332 g_object_unref (new_headers_iter);
1334 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1335 g_object_unref (observer);
1337 /* We no not need to do it the first time,
1338 because it's automatically done by the tree
1340 if (G_LIKELY (!first_time))
1341 tny_folder_poke_status (folder);
1343 g_object_unref (folder);
1345 tny_iterator_next (iter);
1347 g_object_unref (G_OBJECT (iter));
1348 g_source_remove (timeout);
1350 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1351 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1352 new_headers_array->len > 0) {
1356 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1358 /* TODO: Ask the user, instead of just failing,
1359 * showing mail_nc_msg_count_limit_exceeded, with 'Get
1360 * all' and 'Newest only' buttons. */
1361 if (new_headers_array->len > info->retrieve_limit) {
1365 /* Should be get only the headers or the message as well? */
1366 if (g_ascii_strcasecmp (info->retrieve_type,
1367 MODEST_ACCOUNT_RETRIEVE_VALUE_HEADERS_ONLY) != 0) {
1369 priv->total = MIN (new_headers_array->len, info->retrieve_limit);
1370 while (msg_num < priv->total) {
1372 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1373 TnyFolder *folder = tny_header_get_folder (header);
1374 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1375 ModestMailOperationState *state;
1379 /* We can not just use the mail operation because the
1380 values of done and total could change before the
1382 state = modest_mail_operation_clone_state (info->mail_op);
1383 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1384 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1385 pair, (GDestroyNotify) modest_pair_free);
1387 g_object_unref (msg);
1388 g_object_unref (folder);
1395 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1398 /* Copy the headers to a list and free the array */
1399 new_headers = tny_simple_list_new ();
1400 for (i=0; i < new_headers_array->len; i++) {
1401 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1402 tny_list_append (new_headers, G_OBJECT (header));
1404 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1405 g_ptr_array_free (new_headers_array, FALSE);
1408 /* Perform send (if operation was not cancelled) */
1411 if (priv->account != NULL)
1412 g_object_unref (priv->account);
1413 priv->account = g_object_ref (info->transport_account);
1415 send_queue = modest_runtime_get_send_queue (info->transport_account);
1417 modest_tny_send_queue_try_to_send (send_queue);
1419 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1420 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1421 "cannot create a send queue for %s\n",
1422 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1423 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);
1439 if (info->callback) {
1440 UpdateAccountInfo *idle_info;
1442 /* This thread is not in the main lock */
1443 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1444 idle_info->mail_op = g_object_ref (info->mail_op);
1445 idle_info->new_headers = (new_headers) ? g_object_ref (new_headers) : NULL;
1446 idle_info->callback = info->callback;
1447 idle_info->user_data = info->user_data;
1448 g_idle_add (idle_update_account_cb, idle_info);
1451 /* Notify about operation end. Note that the info could be
1452 freed before this idle happens, but the mail operation will
1454 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1458 g_object_unref (new_headers);
1460 g_object_unref (all_folders);
1461 g_object_unref (info->account);
1462 g_object_unref (info->transport_account);
1463 g_free (info->retrieve_type);
1464 g_slice_free (UpdateAccountInfo, info);
1472 modest_mail_operation_update_account (ModestMailOperation *self,
1473 const gchar *account_name,
1474 UpdateAccountCallback callback,
1477 GThread *thread = NULL;
1478 UpdateAccountInfo *info = NULL;
1479 ModestMailOperationPrivate *priv = NULL;
1480 ModestAccountMgr *mgr = NULL;
1481 TnyStoreAccount *store_account = NULL;
1482 TnyTransportAccount *transport_account = NULL;
1484 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1485 g_return_val_if_fail (account_name, FALSE);
1487 /* Init mail operation. Set total and done to 0, and do not
1488 update them, this way the progress objects will know that
1489 we have no clue about the number of the objects */
1490 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1493 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1495 /* Get the store account */
1496 store_account = (TnyStoreAccount *)
1497 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1499 TNY_ACCOUNT_TYPE_STORE);
1501 if (!store_account) {
1502 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1503 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1504 "cannot get tny store account for %s\n", account_name);
1509 /* Get the transport account, we can not do it in the thread
1510 due to some problems with dbus */
1511 transport_account = (TnyTransportAccount *)
1512 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1514 if (!transport_account) {
1515 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1516 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1517 "cannot get tny transport account for %s\n", account_name);
1521 /* Create the helper object */
1522 info = g_slice_new (UpdateAccountInfo);
1523 info->mail_op = self;
1524 info->account = store_account;
1525 info->transport_account = transport_account;
1526 info->callback = callback;
1527 info->user_data = user_data;
1529 /* Get the message size limit */
1530 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1531 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1532 if (info->max_size == 0)
1533 info->max_size = G_MAXINT;
1535 info->max_size = info->max_size * KB;
1537 /* Get per-account retrieval type */
1538 mgr = modest_runtime_get_account_mgr ();
1539 info->retrieve_type = modest_account_mgr_get_retrieve_type (mgr, account_name);
1541 /* Get per-account message amount retrieval limit */
1542 info->retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, account_name);
1543 if (info->retrieve_limit == 0)
1544 info->retrieve_limit = G_MAXINT;
1546 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1548 /* Set account busy */
1549 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1550 priv->account_name = g_strdup(account_name);
1552 modest_mail_operation_notify_start (self);
1553 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1559 g_object_unref (store_account);
1560 if (transport_account)
1561 g_object_unref (transport_account);
1562 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1564 callback (self, NULL, user_data);
1566 modest_mail_operation_notify_end (self);
1570 /* ******************************************************************* */
1571 /* ************************** STORE ACTIONS ************************* */
1572 /* ******************************************************************* */
1576 modest_mail_operation_create_folder (ModestMailOperation *self,
1577 TnyFolderStore *parent,
1580 ModestMailOperationPrivate *priv;
1581 TnyFolder *new_folder = NULL;
1583 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1584 g_return_val_if_fail (name, NULL);
1586 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1588 /* Check for already existing folder */
1589 if (modest_tny_folder_has_subfolder_with_name (parent, name)) {
1590 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1591 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1592 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1593 _CS("ckdg_ib_folder_already_exists"));
1597 if (TNY_IS_FOLDER (parent)) {
1598 /* Check folder rules */
1599 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1600 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1601 /* Set status failed and set an error */
1602 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1603 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1604 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1605 _("mail_in_ui_folder_create_error"));
1609 if (!strcmp (name, " ") || strchr (name, '/')) {
1610 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1611 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1612 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1613 _("mail_in_ui_folder_create_error"));
1617 /* Create the folder */
1618 modest_mail_operation_notify_start (self);
1619 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1620 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1622 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1625 /* Notify about operation end */
1626 modest_mail_operation_notify_end (self);
1632 modest_mail_operation_remove_folder (ModestMailOperation *self,
1634 gboolean remove_to_trash)
1636 TnyAccount *account;
1637 ModestMailOperationPrivate *priv;
1638 ModestTnyFolderRules rules;
1640 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1641 g_return_if_fail (TNY_IS_FOLDER (folder));
1643 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1645 /* Check folder rules */
1646 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1647 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1648 /* Set status failed and set an error */
1649 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1650 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1651 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1652 _("mail_in_ui_folder_delete_error"));
1656 /* Get the account */
1657 account = modest_tny_folder_get_account (folder);
1658 priv->account = g_object_ref(account);
1660 /* Delete folder or move to trash */
1661 if (remove_to_trash) {
1662 TnyFolder *trash_folder = NULL;
1663 trash_folder = modest_tny_account_get_special_folder (account,
1664 TNY_FOLDER_TYPE_TRASH);
1665 /* TODO: error_handling */
1667 modest_mail_operation_notify_start (self);
1668 modest_mail_operation_xfer_folder (self, folder,
1669 TNY_FOLDER_STORE (trash_folder),
1671 g_object_unref (trash_folder);
1674 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1676 modest_mail_operation_notify_start (self);
1677 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1678 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1681 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1684 g_object_unref (G_OBJECT (parent));
1686 g_object_unref (G_OBJECT (account));
1689 /* Notify about operation end */
1690 modest_mail_operation_notify_end (self);
1694 transfer_folder_status_cb (GObject *obj,
1698 ModestMailOperation *self;
1699 ModestMailOperationPrivate *priv;
1700 ModestMailOperationState *state;
1701 XFerMsgAsyncHelper *helper;
1703 g_return_if_fail (status != NULL);
1704 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1706 helper = (XFerMsgAsyncHelper *) user_data;
1707 g_return_if_fail (helper != NULL);
1709 self = helper->mail_op;
1710 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1712 priv->done = status->position;
1713 priv->total = status->of_total;
1715 state = modest_mail_operation_clone_state (self);
1717 /* This is not a GDK lock because we are a Tinymail callback
1718 * which is already GDK locked by Tinymail */
1720 /* no gdk_threads_enter (), CHECKED */
1722 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1724 /* no gdk_threads_leave (), CHECKED */
1726 g_slice_free (ModestMailOperationState, state);
1731 transfer_folder_cb (TnyFolder *folder,
1733 TnyFolderStore *into,
1734 TnyFolder *new_folder,
1738 XFerMsgAsyncHelper *helper;
1739 ModestMailOperation *self = NULL;
1740 ModestMailOperationPrivate *priv = NULL;
1742 helper = (XFerMsgAsyncHelper *) user_data;
1743 g_return_if_fail (helper != NULL);
1745 self = helper->mail_op;
1746 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1749 priv->error = g_error_copy (err);
1751 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1752 } else if (cancelled) {
1753 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1754 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1755 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1756 _("Transference of %s was cancelled."),
1757 tny_folder_get_name (folder));
1760 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1763 /* Notify about operation end */
1764 modest_mail_operation_notify_end (self);
1766 /* If user defined callback function was defined, call it */
1767 if (helper->user_callback) {
1769 /* This is not a GDK lock because we are a Tinymail callback
1770 * which is already GDK locked by Tinymail */
1772 /* no gdk_threads_enter (), CHECKED */
1773 helper->user_callback (self, helper->user_data);
1774 /* no gdk_threads_leave () , CHECKED */
1778 g_object_unref (helper->mail_op);
1779 g_slice_free (XFerMsgAsyncHelper, helper);
1784 * This function checks if the new name is a valid name for our local
1785 * folders account. The new name could not be the same than then name
1786 * of any of the mandatory local folders
1788 * We can not rely on tinymail because tinymail does not check the
1789 * name of the virtual folders that the account could have in the case
1790 * that we're doing a rename (because it directly calls Camel which
1791 * knows nothing about our virtual folders).
1793 * In the case of an actual copy/move (i.e. move/copy a folder between
1794 * accounts) tinymail uses the tny_folder_store_create_account which
1795 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1796 * checks the new name of the folder, so this call in that case
1797 * wouldn't be needed. *But* NOTE that if tinymail changes its
1798 * implementation (if folder transfers within the same account is no
1799 * longer implemented as a rename) this call will allow Modest to work
1802 * If the new name is not valid, this function will set the status to
1803 * failed and will set also an error in the mail operation
1806 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1807 TnyFolderStore *into,
1808 const gchar *new_name)
1810 if (TNY_IS_ACCOUNT (into) &&
1811 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1812 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1814 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1815 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1816 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1817 _("ckdg_ib_folder_already_exists"));
1824 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1826 TnyFolderStore *parent,
1827 gboolean delete_original,
1828 XferAsyncUserCallback user_callback,
1831 ModestMailOperationPrivate *priv = NULL;
1832 ModestTnyFolderRules parent_rules = 0, rules;
1833 XFerMsgAsyncHelper *helper = NULL;
1834 const gchar *folder_name = NULL;
1835 const gchar *error_msg;
1837 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1838 g_return_if_fail (TNY_IS_FOLDER (folder));
1839 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1841 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1842 folder_name = tny_folder_get_name (folder);
1844 /* Set the error msg */
1845 error_msg = _("mail_in_ui_folder_move_target_error");
1847 /* Get account and set it into mail_operation */
1848 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1849 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1851 /* Get folder rules */
1852 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1853 if (TNY_IS_FOLDER (parent))
1854 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1856 /* Apply operation constraints */
1857 if ((gpointer) parent == (gpointer) folder ||
1858 (!TNY_IS_FOLDER_STORE (parent)) ||
1859 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1862 } else if (TNY_IS_FOLDER (parent) &&
1863 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1867 } else if (TNY_IS_FOLDER (parent) &&
1868 TNY_IS_FOLDER_STORE (folder) &&
1869 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1870 TNY_FOLDER_STORE (folder))) {
1871 /* Do not move a parent into a child */
1873 } else if (TNY_IS_FOLDER_STORE (parent) &&
1874 modest_tny_folder_has_subfolder_with_name (parent, folder_name)) {
1875 /* Check that the new folder name is not used by any
1878 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1879 /* Check that the new folder name is not used by any
1880 special local folder */
1883 /* Create the helper */
1884 helper = g_slice_new0 (XFerMsgAsyncHelper);
1885 helper->mail_op = g_object_ref (self);
1886 helper->dest_folder = NULL;
1887 helper->headers = NULL;
1888 helper->user_callback = user_callback;
1889 helper->user_data = user_data;
1891 /* Move/Copy folder */
1892 modest_mail_operation_notify_start (self);
1893 tny_folder_copy_async (folder,
1895 tny_folder_get_name (folder),
1898 transfer_folder_status_cb,
1904 /* Set status failed and set an error */
1905 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1906 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1907 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1910 /* Call the user callback if exists */
1912 user_callback (self, user_data);
1914 /* Notify the queue */
1915 modest_mail_operation_notify_end (self);
1919 modest_mail_operation_rename_folder (ModestMailOperation *self,
1923 ModestMailOperationPrivate *priv;
1924 ModestTnyFolderRules rules;
1925 XFerMsgAsyncHelper *helper;
1927 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1928 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1929 g_return_if_fail (name);
1931 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1933 /* Get account and set it into mail_operation */
1934 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1936 /* Check folder rules */
1937 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1938 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1939 /* Set status failed and set an error */
1940 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1941 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1942 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1943 _("FIXME: unable to rename"));
1945 /* Notify about operation end */
1946 modest_mail_operation_notify_end (self);
1947 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1948 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1949 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1950 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1951 _("FIXME: unable to rename"));
1952 /* Notify about operation end */
1953 modest_mail_operation_notify_end (self);
1955 TnyFolderStore *into;
1957 into = tny_folder_get_folder_store (folder);
1959 /* Check that the new folder name is not used by any
1960 special local folder */
1961 if (new_name_valid_if_local_account (priv, into, name)) {
1962 /* Create the helper */
1963 helper = g_slice_new0 (XFerMsgAsyncHelper);
1964 helper->mail_op = g_object_ref(self);
1965 helper->dest_folder = NULL;
1966 helper->headers = NULL;
1967 helper->user_callback = NULL;
1968 helper->user_data = NULL;
1970 /* Rename. Camel handles folder subscription/unsubscription */
1971 modest_mail_operation_notify_start (self);
1972 tny_folder_copy_async (folder, into, name, TRUE,
1974 transfer_folder_status_cb,
1977 modest_mail_operation_notify_end (self);
1979 g_object_unref (into);
1983 /* ******************************************************************* */
1984 /* ************************** MSG ACTIONS ************************* */
1985 /* ******************************************************************* */
1988 modest_mail_operation_get_msg (ModestMailOperation *self,
1990 GetMsgAsyncUserCallback user_callback,
1993 GetMsgAsyncHelper *helper = NULL;
1995 ModestMailOperationPrivate *priv;
1997 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1998 g_return_if_fail (TNY_IS_HEADER (header));
2000 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2001 folder = tny_header_get_folder (header);
2003 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2005 /* Get message from folder */
2007 /* Get account and set it into mail_operation */
2008 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2010 /* Check for cached messages */
2011 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2012 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2014 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2016 helper = g_slice_new0 (GetMsgAsyncHelper);
2017 helper->mail_op = self;
2018 helper->user_callback = user_callback;
2019 helper->user_data = user_data;
2020 helper->header = g_object_ref (header);
2022 // The callback's reference so that the mail op is not
2023 // finalized until the async operation is completed even if
2024 // the user canceled the request meanwhile.
2025 g_object_ref (G_OBJECT (helper->mail_op));
2027 modest_mail_operation_notify_start (self);
2028 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
2030 g_object_unref (G_OBJECT (folder));
2032 /* Set status failed and set an error */
2033 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2034 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2035 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2036 _("Error trying to get a message. No folder found for header"));
2038 /* Notify the queue */
2039 modest_mail_operation_notify_end (self);
2044 get_msg_cb (TnyFolder *folder,
2050 GetMsgAsyncHelper *helper = NULL;
2051 ModestMailOperation *self = NULL;
2052 ModestMailOperationPrivate *priv = NULL;
2054 helper = (GetMsgAsyncHelper *) user_data;
2055 g_return_if_fail (helper != NULL);
2056 self = helper->mail_op;
2057 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2058 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2060 /* Check errors and cancel */
2062 priv->error = g_error_copy (error);
2063 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2064 } else if (cancelled) {
2065 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2066 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2067 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2068 _("Error trying to refresh the contents of %s"),
2069 tny_folder_get_name (folder));
2071 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2074 /* If user defined callback function was defined, call it even
2075 if the operation failed*/
2076 if (helper->user_callback) {
2077 /* This is not a GDK lock because we are a Tinymail callback
2078 * which is already GDK locked by Tinymail */
2080 /* no gdk_threads_enter (), CHECKED */
2081 helper->user_callback (self, helper->header, msg, helper->user_data);
2082 /* no gdk_threads_leave (), CHECKED */
2085 /* Notify about operation end */
2086 modest_mail_operation_notify_end (self);
2088 g_object_unref (helper->mail_op);
2089 g_object_unref (helper->header);
2090 g_slice_free (GetMsgAsyncHelper, helper);
2095 get_msg_status_cb (GObject *obj,
2099 GetMsgAsyncHelper *helper = NULL;
2100 ModestMailOperation *self;
2101 ModestMailOperationPrivate *priv;
2102 ModestMailOperationState *state;
2104 g_return_if_fail (status != NULL);
2105 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2107 helper = (GetMsgAsyncHelper *) user_data;
2108 g_return_if_fail (helper != NULL);
2110 self = helper->mail_op;
2111 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2116 state = modest_mail_operation_clone_state (self);
2117 state->bytes_done = status->position;
2118 state->bytes_total = status->of_total;
2120 /* This is not a GDK lock because we are a Tinymail callback
2121 * which is already GDK locked by Tinymail */
2123 /* no gdk_threads_enter (), CHECKED */
2124 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2125 /* no gdk_threads_leave (), CHECKED */
2127 g_slice_free (ModestMailOperationState, state);
2130 /****************************************************/
2132 ModestMailOperation *mail_op;
2134 GetMsgAsyncUserCallback user_callback;
2136 GDestroyNotify notify;
2140 GetMsgAsyncUserCallback user_callback;
2144 ModestMailOperation *mail_op;
2145 } NotifyGetMsgsInfo;
2149 * Used by get_msgs_full_thread to call the user_callback for each
2150 * message that has been read
2153 notify_get_msgs_full (gpointer data)
2155 NotifyGetMsgsInfo *info;
2157 info = (NotifyGetMsgsInfo *) data;
2159 /* This is a GDK lock because we are an idle callback and
2160 * because info->user_callback can contain Gtk+ code */
2162 gdk_threads_enter (); /* CHECKED */
2163 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2164 gdk_threads_leave (); /* CHECKED */
2166 g_slice_free (NotifyGetMsgsInfo, info);
2172 * Used by get_msgs_full_thread to free al the thread resources and to
2173 * call the destroy function for the passed user_data
2176 get_msgs_full_destroyer (gpointer data)
2178 GetFullMsgsInfo *info;
2180 info = (GetFullMsgsInfo *) data;
2184 /* This is a GDK lock because we are an idle callback and
2185 * because info->notify can contain Gtk+ code */
2187 gdk_threads_enter (); /* CHECKED */
2188 info->notify (info->user_data);
2189 gdk_threads_leave (); /* CHECKED */
2193 g_object_unref (info->headers);
2194 g_slice_free (GetFullMsgsInfo, info);
2200 get_msgs_full_thread (gpointer thr_user_data)
2202 GetFullMsgsInfo *info;
2203 ModestMailOperationPrivate *priv = NULL;
2204 TnyIterator *iter = NULL;
2206 info = (GetFullMsgsInfo *) thr_user_data;
2207 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2209 iter = tny_list_create_iterator (info->headers);
2210 while (!tny_iterator_is_done (iter)) {
2214 header = TNY_HEADER (tny_iterator_get_current (iter));
2215 folder = tny_header_get_folder (header);
2217 /* Check for cached messages */
2218 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2219 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2221 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2223 /* Get message from folder */
2226 /* The callback will call it per each header */
2227 msg = tny_folder_get_msg (folder, header, &(priv->error));
2230 ModestMailOperationState *state;
2235 /* notify progress */
2236 state = modest_mail_operation_clone_state (info->mail_op);
2237 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2238 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2239 pair, (GDestroyNotify) modest_pair_free);
2241 /* The callback is the responsible for
2242 freeing the message */
2243 if (info->user_callback) {
2244 NotifyGetMsgsInfo *info_notify;
2245 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2246 info_notify->user_callback = info->user_callback;
2247 info_notify->mail_op = info->mail_op;
2248 info_notify->header = g_object_ref (header);
2249 info_notify->msg = g_object_ref (msg);
2250 info_notify->user_data = info->user_data;
2251 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2252 notify_get_msgs_full,
2255 g_object_unref (msg);
2258 /* Set status failed and set an error */
2259 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2260 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2261 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2262 "Error trying to get a message. No folder found for header");
2266 g_object_unref (header);
2268 tny_iterator_next (iter);
2271 /* Set operation status */
2272 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2273 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2275 /* Notify about operation end */
2276 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2278 /* Free thread resources. Will be called after all previous idles */
2279 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2285 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2286 TnyList *header_list,
2287 GetMsgAsyncUserCallback user_callback,
2289 GDestroyNotify notify)
2291 TnyHeader *header = NULL;
2292 TnyFolder *folder = NULL;
2294 ModestMailOperationPrivate *priv = NULL;
2295 GetFullMsgsInfo *info = NULL;
2296 gboolean size_ok = TRUE;
2298 TnyIterator *iter = NULL;
2300 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2302 /* Init mail operation */
2303 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2304 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2306 priv->total = tny_list_get_length(header_list);
2308 /* Get account and set it into mail_operation */
2309 if (tny_list_get_length (header_list) >= 1) {
2310 iter = tny_list_create_iterator (header_list);
2311 header = TNY_HEADER (tny_iterator_get_current (iter));
2313 folder = tny_header_get_folder (header);
2315 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2317 g_object_unref (folder);
2320 g_object_unref (header);
2323 if (tny_list_get_length (header_list) == 1) {
2324 g_object_unref (iter);
2329 /* Get msg size limit */
2330 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2331 MODEST_CONF_MSG_SIZE_LIMIT,
2334 g_clear_error (&(priv->error));
2335 max_size = G_MAXINT;
2337 max_size = max_size * KB;
2340 /* Check message size limits. If there is only one message
2341 always retrieve it */
2343 while (!tny_iterator_is_done (iter) && size_ok) {
2344 header = TNY_HEADER (tny_iterator_get_current (iter));
2346 if (tny_header_get_message_size (header) >= max_size)
2348 g_object_unref (header);
2351 tny_iterator_next (iter);
2353 g_object_unref (iter);
2357 /* Create the info */
2358 info = g_slice_new0 (GetFullMsgsInfo);
2359 info->mail_op = self;
2360 info->user_callback = user_callback;
2361 info->user_data = user_data;
2362 info->headers = g_object_ref (header_list);
2363 info->notify = notify;
2365 modest_mail_operation_notify_start (self);
2366 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2368 /* Set status failed and set an error */
2369 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2370 /* FIXME: the error msg is different for pop */
2371 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2372 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2373 _("emev_ni_ui_imap_msg_size_exceed_error"));
2374 /* Remove from queue and free resources */
2375 modest_mail_operation_notify_end (self);
2383 modest_mail_operation_remove_msg (ModestMailOperation *self,
2385 gboolean remove_to_trash /*ignored*/)
2388 ModestMailOperationPrivate *priv;
2390 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2391 g_return_if_fail (TNY_IS_HEADER (header));
2393 if (remove_to_trash)
2394 g_warning ("remove to trash is not implemented");
2396 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2397 folder = tny_header_get_folder (header);
2399 /* Get account and set it into mail_operation */
2400 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2402 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2404 /* remove message from folder */
2405 tny_folder_remove_msg (folder, header, &(priv->error));
2407 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2408 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2410 modest_mail_operation_notify_start (self);
2412 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2413 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* FALSE --> don't expunge *\/ */
2414 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2415 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2416 /* tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* TRUE --> dont expunge *\/ */
2417 tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2420 /* tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /\* TRUE --> expunge *\/ */
2421 tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2427 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2429 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2432 g_object_unref (G_OBJECT (folder));
2434 /* Notify about operation end */
2435 modest_mail_operation_notify_end (self);
2439 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2441 gboolean remove_to_trash /*ignored*/)
2444 ModestMailOperationPrivate *priv;
2445 TnyIterator *iter = NULL;
2446 TnyHeader *header = NULL;
2448 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2449 g_return_if_fail (TNY_IS_LIST (headers));
2451 if (remove_to_trash)
2452 g_warning ("remove to trash is not implemented");
2454 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2456 /* Get folder from first header and sync it */
2457 iter = tny_list_create_iterator (headers);
2458 header = TNY_HEADER (tny_iterator_get_current (iter));
2459 folder = tny_header_get_folder (header);
2461 /* Get account and set it into mail_operation */
2462 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2464 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2466 /* remove message from folder */
2467 modest_mail_operation_notify_start (self);
2469 tny_folder_remove_msgs (folder, headers, &(priv->error));
2471 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2472 TNY_IS_CAMEL_POP_FOLDER (folder))
2473 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> don't expunge */
2476 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2482 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2484 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2487 g_object_unref (header);
2488 g_object_unref (iter);
2489 g_object_unref (G_OBJECT (folder));
2491 /* Notify about operation end */
2492 modest_mail_operation_notify_end (self);
2497 transfer_msgs_status_cb (GObject *obj,
2501 XFerMsgAsyncHelper *helper = NULL;
2502 ModestMailOperation *self;
2503 ModestMailOperationPrivate *priv;
2504 ModestMailOperationState *state;
2507 g_return_if_fail (status != NULL);
2508 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2510 helper = (XFerMsgAsyncHelper *) user_data;
2511 g_return_if_fail (helper != NULL);
2513 self = helper->mail_op;
2514 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2516 priv->done = status->position;
2517 priv->total = status->of_total;
2519 state = modest_mail_operation_clone_state (self);
2521 /* This is not a GDK lock because we are a Tinymail callback and
2522 * Tinymail already acquires the Gdk lock */
2524 /* no gdk_threads_enter (), CHECKED */
2526 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2528 /* no gdk_threads_leave (), CHECKED */
2530 g_slice_free (ModestMailOperationState, state);
2535 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2537 XFerMsgAsyncHelper *helper;
2538 ModestMailOperation *self;
2539 ModestMailOperationPrivate *priv;
2540 TnyIterator *iter = NULL;
2541 TnyHeader *header = NULL;
2543 helper = (XFerMsgAsyncHelper *) user_data;
2544 self = helper->mail_op;
2546 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2549 priv->error = g_error_copy (err);
2551 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2552 } else if (cancelled) {
2553 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2554 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2555 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2556 _("Error trying to refresh the contents of %s"),
2557 tny_folder_get_name (folder));
2560 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2562 /* Update folder counts */
2563 tny_folder_poke_status (folder);
2564 tny_folder_poke_status (helper->dest_folder);
2568 /* Mark headers as deleted and seen */
2569 if ((helper->delete) &&
2570 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2571 iter = tny_list_create_iterator (helper->headers);
2572 while (!tny_iterator_is_done (iter)) {
2573 header = TNY_HEADER (tny_iterator_get_current (iter));
2574 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2575 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2576 g_object_unref (header);
2578 tny_iterator_next (iter);
2584 /* Notify about operation end */
2585 modest_mail_operation_notify_end (self);
2587 /* If user defined callback function was defined, call it */
2588 if (helper->user_callback) {
2589 /* This is not a GDK lock because we are a Tinymail callback and
2590 * Tinymail already acquires the Gdk lock */
2592 /* no gdk_threads_enter (), CHECKED */
2593 helper->user_callback (self, helper->user_data);
2594 /* no gdk_threads_leave (), CHECKED */
2598 if (helper->headers)
2599 g_object_unref (helper->headers);
2600 if (helper->dest_folder)
2601 g_object_unref (helper->dest_folder);
2602 if (helper->mail_op)
2603 g_object_unref (helper->mail_op);
2605 g_object_unref (folder);
2607 g_object_unref (iter);
2608 g_slice_free (XFerMsgAsyncHelper, helper);
2612 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2615 gboolean delete_original,
2616 XferAsyncUserCallback user_callback,
2619 ModestMailOperationPrivate *priv = NULL;
2620 TnyIterator *iter = NULL;
2621 TnyFolder *src_folder = NULL;
2622 XFerMsgAsyncHelper *helper = NULL;
2623 TnyHeader *header = NULL;
2624 ModestTnyFolderRules rules = 0;
2626 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2627 g_return_if_fail (TNY_IS_LIST (headers));
2628 g_return_if_fail (TNY_IS_FOLDER (folder));
2630 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2633 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2635 /* Apply folder rules */
2636 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2637 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2638 /* Set status failed and set an error */
2639 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2640 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2641 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2642 _CS("ckct_ib_unable_to_paste_here"));
2643 /* Notify the queue */
2644 modest_mail_operation_notify_end (self);
2648 /* Get source folder */
2649 iter = tny_list_create_iterator (headers);
2650 header = TNY_HEADER (tny_iterator_get_current (iter));
2652 src_folder = tny_header_get_folder (header);
2653 g_object_unref (header);
2656 g_object_unref (iter);
2658 /* Check folder source and destination */
2659 if (src_folder == folder) {
2660 /* Set status failed and set an error */
2661 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2662 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2663 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2664 _("mcen_ib_unable_to_copy_samefolder"));
2666 /* Notify the queue */
2667 modest_mail_operation_notify_end (self);
2670 g_object_unref (src_folder);
2674 /* Create the helper */
2675 helper = g_slice_new0 (XFerMsgAsyncHelper);
2676 helper->mail_op = g_object_ref(self);
2677 helper->dest_folder = g_object_ref(folder);
2678 helper->headers = g_object_ref(headers);
2679 helper->user_callback = user_callback;
2680 helper->user_data = user_data;
2681 helper->delete = delete_original;
2683 /* Get account and set it into mail_operation */
2684 priv->account = modest_tny_folder_get_account (src_folder);
2686 /* Transfer messages */
2687 modest_mail_operation_notify_start (self);
2688 tny_folder_transfer_msgs_async (src_folder,
2693 transfer_msgs_status_cb,
2699 on_refresh_folder (TnyFolder *folder,
2704 RefreshAsyncHelper *helper = NULL;
2705 ModestMailOperation *self = NULL;
2706 ModestMailOperationPrivate *priv = NULL;
2708 helper = (RefreshAsyncHelper *) user_data;
2709 self = helper->mail_op;
2710 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2712 g_return_if_fail(priv!=NULL);
2715 priv->error = g_error_copy (error);
2716 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2717 printf("DEBUG: %s: Operation error:\n %s", __FUNCTION__,
2723 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2724 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2725 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2726 _("Error trying to refresh the contents of %s"),
2727 tny_folder_get_name (folder));
2728 printf("DEBUG: %s: Operation cancelled.\n", __FUNCTION__);
2732 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2734 /* Call user defined callback, if it exists */
2735 if (helper->user_callback) {
2737 /* This is not a GDK lock because we are a Tinymail callback and
2738 * Tinymail already acquires the Gdk lock */
2739 helper->user_callback (self, folder, helper->user_data);
2744 g_slice_free (RefreshAsyncHelper, helper);
2746 /* Notify about operation end */
2747 modest_mail_operation_notify_end (self);
2748 g_object_unref(self);
2752 on_refresh_folder_status_update (GObject *obj,
2756 RefreshAsyncHelper *helper = NULL;
2757 ModestMailOperation *self = NULL;
2758 ModestMailOperationPrivate *priv = NULL;
2759 ModestMailOperationState *state;
2761 g_return_if_fail (user_data != NULL);
2762 g_return_if_fail (status != NULL);
2763 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2765 helper = (RefreshAsyncHelper *) user_data;
2766 self = helper->mail_op;
2767 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2769 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2771 priv->done = status->position;
2772 priv->total = status->of_total;
2774 state = modest_mail_operation_clone_state (self);
2776 /* This is not a GDK lock because we are a Tinymail callback and
2777 * Tinymail already acquires the Gdk lock */
2778 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2780 g_slice_free (ModestMailOperationState, state);
2784 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2786 RefreshAsyncUserCallback user_callback,
2789 ModestMailOperationPrivate *priv = NULL;
2790 RefreshAsyncHelper *helper = NULL;
2792 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2794 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2796 /* Get account and set it into mail_operation */
2797 priv->account = modest_tny_folder_get_account (folder);
2799 /* Create the helper */
2800 helper = g_slice_new0 (RefreshAsyncHelper);
2801 helper->mail_op = g_object_ref(self);
2802 helper->user_callback = user_callback;
2803 helper->user_data = user_data;
2805 /* Refresh the folder. TODO: tinymail could issue a status
2806 updates before the callback call then this could happen. We
2807 must review the design */
2808 modest_mail_operation_notify_start (self);
2809 tny_folder_refresh_async (folder,
2811 on_refresh_folder_status_update,
2817 modest_mail_operation_notify_start (ModestMailOperation *self)
2819 ModestMailOperationPrivate *priv = NULL;
2821 g_return_if_fail (self);
2823 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2825 /* Ensure that all the fields are filled correctly */
2826 /* g_return_if_fail (priv->account != NULL); */
2827 /* g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN); */
2828 g_assert (priv->account != NULL);
2829 g_assert (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 /* Set the account back to not busy */
2855 if (priv->account_name) {
2856 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2857 priv->account_name, FALSE);
2858 g_free(priv->account_name);
2859 priv->account_name = NULL;
2862 /* Notify the observers about the mail operation end. We do
2863 not wrapp this emission because we assume that this
2864 function is always called from within the main lock */
2865 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
2869 modest_mail_operation_get_account (ModestMailOperation *self)
2871 ModestMailOperationPrivate *priv = NULL;
2873 g_return_val_if_fail (self, NULL);
2875 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2877 return (priv->account) ? g_object_ref (priv->account) : NULL;