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_async_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 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
89 gint *last_total_bytes,
90 gint *sum_total_bytes,
92 gboolean increment_done);
94 static guint compute_message_list_size (TnyList *headers);
96 static guint compute_message_array_size (GPtrArray *headers);
98 static int compare_headers_by_date (gconstpointer a,
101 enum _ModestMailOperationSignals
103 PROGRESS_CHANGED_SIGNAL,
104 OPERATION_STARTED_SIGNAL,
105 OPERATION_FINISHED_SIGNAL,
109 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
110 struct _ModestMailOperationPrivate {
116 ErrorCheckingUserCallback error_checking;
117 gpointer error_checking_user_data;
118 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
119 ModestMailOperationStatus status;
120 ModestMailOperationTypeOperation op_type;
123 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
124 MODEST_TYPE_MAIL_OPERATION, \
125 ModestMailOperationPrivate))
127 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
128 priv->status = new_status;\
133 GetMsgAsyncUserCallback user_callback;
136 ModestMailOperation *mail_op;
137 GDestroyNotify destroy_notify;
138 gint last_total_bytes;
139 gint sum_total_bytes;
144 ModestMailOperation *mail_op;
146 gulong msg_sent_handler;
147 gulong error_happened_handler;
150 static void send_mail_msg_sent_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
151 guint nth, guint total, gpointer userdata);
152 static void send_mail_error_happened_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
153 GError *error, gpointer userdata);
154 static void common_send_mail_operation_end (TnySendQueue *queue, TnyMsg *msg,
157 typedef struct _RefreshAsyncHelper {
158 ModestMailOperation *mail_op;
159 RefreshAsyncUserCallback user_callback;
161 } RefreshAsyncHelper;
163 typedef struct _XFerMsgAsyncHelper
165 ModestMailOperation *mail_op;
167 TnyFolder *dest_folder;
168 XferAsyncUserCallback user_callback;
171 gint last_total_bytes;
172 gint sum_total_bytes;
174 } XFerMsgAsyncHelper;
176 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
180 static void modest_mail_operation_create_msg (ModestMailOperation *self,
181 const gchar *from, const gchar *to,
182 const gchar *cc, const gchar *bcc,
183 const gchar *subject, const gchar *plain_body,
184 const gchar *html_body, const GList *attachments_list,
185 const GList *images_list,
186 TnyHeaderFlags priority_flags,
187 ModestMailOperationCreateMsgCallback callback,
190 static gboolean idle_notify_queue (gpointer data);
193 ModestMailOperation *mail_op;
201 GList *attachments_list;
203 TnyHeaderFlags priority_flags;
204 ModestMailOperationCreateMsgCallback callback;
210 ModestMailOperation *mail_op;
212 ModestMailOperationCreateMsgCallback callback;
217 static GObjectClass *parent_class = NULL;
219 static guint signals[NUM_SIGNALS] = {0};
222 modest_mail_operation_get_type (void)
224 static GType my_type = 0;
226 static const GTypeInfo my_info = {
227 sizeof(ModestMailOperationClass),
228 NULL, /* base init */
229 NULL, /* base finalize */
230 (GClassInitFunc) modest_mail_operation_class_init,
231 NULL, /* class finalize */
232 NULL, /* class data */
233 sizeof(ModestMailOperation),
235 (GInstanceInitFunc) modest_mail_operation_init,
238 my_type = g_type_register_static (G_TYPE_OBJECT,
239 "ModestMailOperation",
246 modest_mail_operation_class_init (ModestMailOperationClass *klass)
248 GObjectClass *gobject_class;
249 gobject_class = (GObjectClass*) klass;
251 parent_class = g_type_class_peek_parent (klass);
252 gobject_class->finalize = modest_mail_operation_finalize;
254 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
257 * ModestMailOperation::progress-changed
258 * @self: the #MailOperation that emits the signal
259 * @user_data: user data set when the signal handler was connected
261 * Emitted when the progress of a mail operation changes
263 signals[PROGRESS_CHANGED_SIGNAL] =
264 g_signal_new ("progress-changed",
265 G_TYPE_FROM_CLASS (gobject_class),
267 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
269 g_cclosure_marshal_VOID__POINTER,
270 G_TYPE_NONE, 1, G_TYPE_POINTER);
274 * This signal is issued whenever a mail operation starts, and
275 * starts mean when the tinymail operation is issued. This
276 * means that it could happen that something wrong happens and
277 * the tinymail function is never called. In this situation a
278 * operation-finished will be issued without any
281 signals[OPERATION_STARTED_SIGNAL] =
282 g_signal_new ("operation-started",
283 G_TYPE_FROM_CLASS (gobject_class),
285 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
287 g_cclosure_marshal_VOID__VOID,
292 * This signal is issued whenever a mail operation
293 * finishes. Note that this signal could be issued without any
294 * previous "operation-started" signal, because this last one
295 * is only issued when the tinymail operation is successfully
298 signals[OPERATION_FINISHED_SIGNAL] =
299 g_signal_new ("operation-finished",
300 G_TYPE_FROM_CLASS (gobject_class),
302 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
304 g_cclosure_marshal_VOID__VOID,
309 modest_mail_operation_init (ModestMailOperation *obj)
311 ModestMailOperationPrivate *priv;
313 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
315 priv->account = NULL;
316 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
317 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
322 priv->error_checking = NULL;
323 priv->error_checking_user_data = NULL;
327 modest_mail_operation_finalize (GObject *obj)
329 ModestMailOperationPrivate *priv;
331 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
336 g_error_free (priv->error);
340 g_object_unref (priv->source);
344 g_object_unref (priv->account);
345 priv->account = NULL;
349 G_OBJECT_CLASS(parent_class)->finalize (obj);
353 modest_mail_operation_new (GObject *source)
355 ModestMailOperation *obj;
356 ModestMailOperationPrivate *priv;
358 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
359 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
362 priv->source = g_object_ref(source);
368 modest_mail_operation_new_with_error_handling (GObject *source,
369 ErrorCheckingUserCallback error_handler,
371 ErrorCheckingUserDataDestroyer error_handler_destroyer)
373 ModestMailOperation *obj;
374 ModestMailOperationPrivate *priv;
376 obj = modest_mail_operation_new (source);
377 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
379 g_return_val_if_fail (error_handler != NULL, obj);
380 priv->error_checking = error_handler;
381 priv->error_checking_user_data = user_data;
382 priv->error_checking_user_data_destroyer = error_handler_destroyer;
388 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
390 ModestMailOperationPrivate *priv;
392 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
394 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
395 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
397 /* Call the user callback */
398 if (priv->error_checking != NULL)
399 priv->error_checking (self, priv->error_checking_user_data);
403 ModestMailOperationTypeOperation
404 modest_mail_operation_get_type_operation (ModestMailOperation *self)
406 ModestMailOperationPrivate *priv;
408 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
409 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
411 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
413 return priv->op_type;
417 modest_mail_operation_is_mine (ModestMailOperation *self,
420 ModestMailOperationPrivate *priv;
422 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
425 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
426 if (priv->source == NULL) return FALSE;
428 return priv->source == me;
432 modest_mail_operation_get_source (ModestMailOperation *self)
434 ModestMailOperationPrivate *priv;
436 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
439 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
441 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
445 return (priv->source) ? g_object_ref (priv->source) : NULL;
448 ModestMailOperationStatus
449 modest_mail_operation_get_status (ModestMailOperation *self)
451 ModestMailOperationPrivate *priv;
453 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
454 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
455 MODEST_MAIL_OPERATION_STATUS_INVALID);
457 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
459 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
460 return MODEST_MAIL_OPERATION_STATUS_INVALID;
467 modest_mail_operation_get_error (ModestMailOperation *self)
469 ModestMailOperationPrivate *priv;
471 g_return_val_if_fail (self, NULL);
472 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
474 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
477 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
485 modest_mail_operation_cancel (ModestMailOperation *self)
487 ModestMailOperationPrivate *priv;
488 gboolean canceled = FALSE;
490 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
492 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
494 /* Note that if we call cancel with an already canceled mail
495 operation the progress changed signal won't be emitted */
496 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
500 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
502 /* Cancel the mail operation. We need to wrap it between this
503 start/stop operations to allow following calls to the
505 g_return_val_if_fail (priv->account, FALSE);
507 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
508 ModestTnySendQueue *queue;
509 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account));
510 /* Cancel sending without removing the item */
511 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), FALSE, NULL);
513 /* Cancel operation */
514 tny_account_cancel (priv->account);
521 modest_mail_operation_get_task_done (ModestMailOperation *self)
523 ModestMailOperationPrivate *priv;
525 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
528 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
533 modest_mail_operation_get_task_total (ModestMailOperation *self)
535 ModestMailOperationPrivate *priv;
537 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
540 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
545 modest_mail_operation_is_finished (ModestMailOperation *self)
547 ModestMailOperationPrivate *priv;
548 gboolean retval = FALSE;
550 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
553 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
555 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
556 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
557 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
558 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
568 * Creates an image of the current state of a mail operation, the
569 * caller must free it
571 static ModestMailOperationState *
572 modest_mail_operation_clone_state (ModestMailOperation *self)
574 ModestMailOperationState *state;
575 ModestMailOperationPrivate *priv;
577 /* FIXME: this should be fixed properly
579 * in some cases, priv was NULL, so checking here to
582 g_return_val_if_fail (self, NULL);
583 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
584 g_return_val_if_fail (priv, NULL);
589 state = g_slice_new (ModestMailOperationState);
591 state->status = priv->status;
592 state->op_type = priv->op_type;
593 state->done = priv->done;
594 state->total = priv->total;
595 state->finished = modest_mail_operation_is_finished (self);
596 state->bytes_done = 0;
597 state->bytes_total = 0;
602 /* ******************************************************************* */
603 /* ************************** SEND ACTIONS ************************* */
604 /* ******************************************************************* */
607 modest_mail_operation_send_mail (ModestMailOperation *self,
608 TnyTransportAccount *transport_account,
611 TnySendQueue *send_queue = NULL;
612 ModestMailOperationPrivate *priv;
615 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
616 g_return_if_fail (transport_account && TNY_IS_TRANSPORT_ACCOUNT (transport_account));
617 g_return_if_fail (msg && TNY_IS_MSG (msg));
619 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
621 /* Get account and set it into mail_operation */
622 priv->account = g_object_ref (transport_account);
623 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
627 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
628 if (!TNY_IS_SEND_QUEUE(send_queue)) {
629 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
630 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
631 "modest: could not find send queue for account\n");
632 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
633 modest_mail_operation_notify_end (self);
636 /* Add the msg to the queue */
637 modest_mail_operation_notify_start (self);
638 modest_tny_send_queue_add (MODEST_TNY_SEND_QUEUE(send_queue),
642 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
644 info = g_slice_new0 (SendMsgInfo);
646 info->mail_op = g_object_ref (self);
647 info->msg = g_object_ref (msg);
648 info->msg_sent_handler = g_signal_connect (G_OBJECT (send_queue), "msg-sent",
649 G_CALLBACK (send_mail_msg_sent_handler), info);
650 info->error_happened_handler = g_signal_connect (G_OBJECT (send_queue), "error-happened",
651 G_CALLBACK (send_mail_error_happened_handler), info);
657 common_send_mail_operation_end (TnySendQueue *queue, TnyMsg *msg,
660 g_signal_handler_disconnect (queue, info->msg_sent_handler);
661 g_signal_handler_disconnect (queue, info->error_happened_handler);
663 g_object_unref (info->msg);
664 modest_mail_operation_notify_end (info->mail_op);
665 g_object_unref (info->mail_op);
667 g_slice_free (SendMsgInfo, info);
671 send_mail_msg_sent_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
672 guint nth, guint total, gpointer userdata)
674 SendMsgInfo *info = (SendMsgInfo *) userdata;
676 if (!strcmp (tny_msg_get_url_string (msg),
677 tny_msg_get_url_string (info->msg))) {
678 ModestMailOperationPrivate *priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
679 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
681 common_send_mail_operation_end (queue, msg, info);
686 send_mail_error_happened_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
687 GError *error, gpointer userdata)
689 SendMsgInfo *info = (SendMsgInfo *) userdata;
691 if (!strcmp (tny_msg_get_url_string (msg),
692 tny_msg_get_url_string (info->msg))) {
693 ModestMailOperationPrivate *priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
694 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
695 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
696 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
697 "modest: send mail failed\n");
699 common_send_mail_operation_end (queue, msg, info);
705 idle_create_msg_cb (gpointer idle_data)
707 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
709 /* This is a GDK lock because we are an idle callback and
710 * info->callback can contain Gtk+ code */
712 gdk_threads_enter (); /* CHECKED */
713 info->callback (info->mail_op, info->msg, info->userdata);
715 g_object_unref (info->mail_op);
717 g_object_unref (info->msg);
718 g_slice_free (CreateMsgIdleInfo, info);
719 gdk_threads_leave (); /* CHECKED */
725 create_msg_thread (gpointer thread_data)
727 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
728 TnyMsg *new_msg = NULL;
729 ModestMailOperationPrivate *priv;
731 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
732 if (info->html_body == NULL) {
733 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
734 info->bcc, info->subject, info->plain_body,
735 info->attachments_list);
737 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
738 info->bcc, info->subject, info->html_body,
739 info->plain_body, info->attachments_list,
746 /* Set priority flags in message */
747 header = tny_msg_get_header (new_msg);
748 tny_header_set_flag (header, info->priority_flags);
750 /* Set attachment flags in message */
751 if (info->attachments_list != NULL)
752 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
754 g_object_unref (G_OBJECT(header));
756 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
757 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
758 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
759 "modest: failed to create a new msg\n");
767 g_free (info->plain_body);
768 g_free (info->html_body);
769 g_free (info->subject);
770 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
771 g_list_free (info->attachments_list);
772 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
773 g_list_free (info->images_list);
775 if (info->callback) {
776 CreateMsgIdleInfo *idle_info;
777 idle_info = g_slice_new0 (CreateMsgIdleInfo);
778 idle_info->mail_op = g_object_ref (info->mail_op);
779 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
780 idle_info->callback = info->callback;
781 idle_info->userdata = info->userdata;
782 g_idle_add (idle_create_msg_cb, idle_info);
784 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
787 g_object_unref (info->mail_op);
788 g_slice_free (CreateMsgInfo, info);
793 modest_mail_operation_create_msg (ModestMailOperation *self,
794 const gchar *from, const gchar *to,
795 const gchar *cc, const gchar *bcc,
796 const gchar *subject, const gchar *plain_body,
797 const gchar *html_body,
798 const GList *attachments_list,
799 const GList *images_list,
800 TnyHeaderFlags priority_flags,
801 ModestMailOperationCreateMsgCallback callback,
804 CreateMsgInfo *info = NULL;
806 info = g_slice_new0 (CreateMsgInfo);
807 info->mail_op = g_object_ref (self);
809 info->from = g_strdup (from);
810 info->to = g_strdup (to);
811 info->cc = g_strdup (cc);
812 info->bcc = g_strdup (bcc);
813 info->subject = g_strdup (subject);
814 info->plain_body = g_strdup (plain_body);
815 info->html_body = g_strdup (html_body);
816 info->attachments_list = g_list_copy ((GList *) attachments_list);
817 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
818 info->images_list = g_list_copy ((GList *) images_list);
819 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
820 info->priority_flags = priority_flags;
822 info->callback = callback;
823 info->userdata = userdata;
825 g_thread_create (create_msg_thread, info, FALSE, NULL);
830 TnyTransportAccount *transport_account;
835 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
839 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
840 TnyFolder *draft_folder = NULL;
841 TnyFolder *outbox_folder = NULL;
849 /* Call mail operation */
850 modest_mail_operation_send_mail (self, info->transport_account, msg);
852 /* Remove old mail from its source folder */
853 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
854 TNY_FOLDER_TYPE_DRAFTS);
855 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
856 TNY_FOLDER_TYPE_OUTBOX);
857 if (info->draft_msg != NULL) {
858 TnyFolder *folder = NULL;
859 TnyFolder *src_folder = NULL;
860 TnyFolderType folder_type;
861 folder = tny_msg_get_folder (info->draft_msg);
862 if (folder == NULL) goto end;
863 folder_type = modest_tny_folder_guess_folder_type (folder);
865 if (folder_type == TNY_FOLDER_TYPE_INVALID)
866 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
868 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
869 src_folder = outbox_folder;
871 src_folder = draft_folder;
873 /* Note: This can fail (with a warning) if the message is not really already in a folder,
874 * because this function requires it to have a UID. */
875 header = tny_msg_get_header (info->draft_msg);
876 tny_folder_remove_msg (src_folder, header, NULL);
878 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
879 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
881 g_object_unref (header);
882 g_object_unref (folder);
889 g_object_unref (info->draft_msg);
891 g_object_unref (draft_folder);
893 g_object_unref (outbox_folder);
894 if (info->transport_account)
895 g_object_unref (info->transport_account);
896 g_slice_free (SendNewMailInfo, info);
900 modest_mail_operation_send_new_mail (ModestMailOperation *self,
901 TnyTransportAccount *transport_account,
903 const gchar *from, const gchar *to,
904 const gchar *cc, const gchar *bcc,
905 const gchar *subject, const gchar *plain_body,
906 const gchar *html_body,
907 const GList *attachments_list,
908 const GList *images_list,
909 TnyHeaderFlags priority_flags)
911 ModestMailOperationPrivate *priv = NULL;
912 SendNewMailInfo *info;
914 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
915 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
917 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
918 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
919 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
920 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
922 /* Check parametters */
924 /* Set status failed and set an error */
925 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
926 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
927 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
928 _("Error trying to send a mail. You need to set at least one recipient"));
931 info = g_slice_new0 (SendNewMailInfo);
932 info->transport_account = transport_account;
933 if (transport_account)
934 g_object_ref (transport_account);
935 info->draft_msg = draft_msg;
937 g_object_ref (draft_msg);
940 modest_mail_operation_notify_start (self);
941 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
942 attachments_list, images_list, priority_flags,
943 modest_mail_operation_send_new_mail_cb, info);
949 TnyTransportAccount *transport_account;
951 SaveToDraftstCallback callback;
955 ModestMailOperation *mailop;
956 } SaveToDraftsAddMsgInfo;
959 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
964 ModestMailOperationPrivate *priv = NULL;
965 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
967 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
970 g_warning ("%s: priv->error != NULL", __FUNCTION__);
971 g_error_free(priv->error);
974 priv->error = (err == NULL) ? NULL : g_error_copy(err);
976 if ((!priv->error) && (info->draft_msg != NULL)) {
977 TnyHeader *header = tny_msg_get_header (info->draft_msg);
978 TnyFolder *src_folder = tny_header_get_folder (header);
980 /* Remove the old draft */
981 tny_folder_remove_msg (src_folder, header, NULL);
983 /* Synchronize to expunge and to update the msg counts */
984 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
985 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
987 g_object_unref (G_OBJECT(header));
988 g_object_unref (G_OBJECT(src_folder));
992 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
994 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
996 /* Call the user callback */
998 info->callback (info->mailop, info->msg, info->user_data);
1000 if (info->transport_account)
1001 g_object_unref (G_OBJECT(info->transport_account));
1002 if (info->draft_msg)
1003 g_object_unref (G_OBJECT (info->draft_msg));
1005 g_object_unref (G_OBJECT(info->drafts));
1007 g_object_unref (G_OBJECT (info->msg));
1008 g_slice_free (SaveToDraftsAddMsgInfo, info);
1010 modest_mail_operation_notify_end (info->mailop);
1011 g_object_unref(info->mailop);
1016 TnyTransportAccount *transport_account;
1018 SaveToDraftstCallback callback;
1023 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1027 TnyFolder *drafts = NULL;
1028 ModestMailOperationPrivate *priv = NULL;
1029 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1031 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1034 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1035 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1036 "modest: failed to create a new msg\n");
1038 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1039 TNY_FOLDER_TYPE_DRAFTS);
1041 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1042 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1043 "modest: failed to create a new msg\n");
1048 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1049 cb_info->transport_account = g_object_ref(info->transport_account);
1050 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1051 cb_info->callback = info->callback;
1052 cb_info->user_data = info->user_data;
1053 cb_info->drafts = g_object_ref(drafts);
1054 cb_info->msg = g_object_ref(msg);
1055 cb_info->mailop = g_object_ref(self);
1056 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1059 /* Call the user callback */
1060 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1062 info->callback (self, msg, info->user_data);
1063 modest_mail_operation_notify_end (self);
1067 g_object_unref (G_OBJECT(drafts));
1068 if (info->draft_msg)
1069 g_object_unref (G_OBJECT (info->draft_msg));
1070 if (info->transport_account)
1071 g_object_unref (G_OBJECT(info->transport_account));
1072 g_slice_free (SaveToDraftsInfo, info);
1076 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1077 TnyTransportAccount *transport_account,
1079 const gchar *from, const gchar *to,
1080 const gchar *cc, const gchar *bcc,
1081 const gchar *subject, const gchar *plain_body,
1082 const gchar *html_body,
1083 const GList *attachments_list,
1084 const GList *images_list,
1085 TnyHeaderFlags priority_flags,
1086 SaveToDraftstCallback callback,
1089 ModestMailOperationPrivate *priv = NULL;
1090 SaveToDraftsInfo *info = NULL;
1092 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1093 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1095 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1097 /* Get account and set it into mail_operation */
1098 priv->account = g_object_ref (transport_account);
1099 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1101 info = g_slice_new0 (SaveToDraftsInfo);
1102 info->transport_account = g_object_ref (transport_account);
1103 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1104 info->callback = callback;
1105 info->user_data = user_data;
1107 modest_mail_operation_notify_start (self);
1108 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1109 attachments_list, images_list, priority_flags,
1110 modest_mail_operation_save_to_drafts_cb, info);
1115 ModestMailOperation *mail_op;
1116 TnyMimePart *mime_part;
1118 GetMimePartSizeCallback callback;
1120 } GetMimePartSizeInfo;
1122 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1123 /* We use this folder observer to track the headers that have been
1124 * added to a folder */
1127 TnyList *new_headers;
1128 } InternalFolderObserver;
1131 GObjectClass parent;
1132 } InternalFolderObserverClass;
1134 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1136 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1137 internal_folder_observer,
1139 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1143 foreach_add_item (gpointer header, gpointer user_data)
1145 tny_list_prepend (TNY_LIST (user_data),
1146 g_object_ref (G_OBJECT (header)));
1149 /* This is the method that looks for new messages in a folder */
1151 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1153 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1155 TnyFolderChangeChanged changed;
1157 changed = tny_folder_change_get_changed (change);
1159 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1162 /* Get added headers */
1163 list = tny_simple_list_new ();
1164 tny_folder_change_get_added_headers (change, list);
1166 /* Add them to the folder observer */
1167 tny_list_foreach (list, foreach_add_item,
1168 derived->new_headers);
1170 g_object_unref (G_OBJECT (list));
1175 internal_folder_observer_init (InternalFolderObserver *self)
1177 self->new_headers = tny_simple_list_new ();
1180 internal_folder_observer_finalize (GObject *object)
1182 InternalFolderObserver *self;
1184 self = (InternalFolderObserver *) object;
1185 g_object_unref (self->new_headers);
1187 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1190 tny_folder_observer_init (TnyFolderObserverIface *iface)
1192 iface->update_func = internal_folder_observer_update;
1195 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1197 GObjectClass *object_class;
1199 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1200 object_class = (GObjectClass*) klass;
1201 object_class->finalize = internal_folder_observer_finalize;
1206 ModestMailOperation *mail_op;
1207 gchar *account_name;
1208 UpdateAccountCallback callback;
1213 TnyFolderObserver *inbox_observer;
1214 guint update_timeout;
1215 } UpdateAccountInfo;
1219 destroy_update_account_info (UpdateAccountInfo *info)
1221 if (info->update_timeout) {
1222 g_source_remove (info->update_timeout);
1223 info->update_timeout = 0;
1226 g_free (info->account_name);
1227 g_object_unref (info->folders);
1228 g_object_unref (info->mail_op);
1229 g_slice_free (UpdateAccountInfo, info);
1233 update_account_get_msg_async_cb (TnyFolder *folder,
1239 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1241 /* Just delete the helper. Don't do anything with the new
1242 msg. There is also no need to check for errors */
1243 g_object_unref (msg_info->mail_op);
1244 g_object_unref (msg_info->header);
1245 g_slice_free (GetMsgInfo, msg_info);
1250 inbox_refreshed_cb (TnyFolder *inbox,
1255 UpdateAccountInfo *info;
1256 ModestMailOperationPrivate *priv;
1257 TnyIterator *new_headers_iter;
1258 GPtrArray *new_headers_array = NULL;
1259 gint max_size, retrieve_limit, i;
1260 ModestAccountMgr *mgr;
1261 gchar *retrieve_type = NULL;
1262 TnyList *new_headers = NULL;
1263 gboolean headers_only;
1264 TnyTransportAccount *transport_account;
1265 ModestTnySendQueue *send_queue;
1267 info = (UpdateAccountInfo *) user_data;
1268 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1269 mgr = modest_runtime_get_account_mgr ();
1271 if (canceled || err || !inbox) {
1272 /* Try to send anyway */
1276 /* Get the message max size */
1277 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1278 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1280 max_size = G_MAXINT;
1282 max_size = max_size * KB;
1284 /* Create the new headers array. We need it to sort the
1285 new headers by date */
1286 new_headers_array = g_ptr_array_new ();
1287 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1288 while (!tny_iterator_is_done (new_headers_iter)) {
1289 TnyHeader *header = NULL;
1291 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1292 /* Apply per-message size limits */
1293 if (tny_header_get_message_size (header) < max_size)
1294 g_ptr_array_add (new_headers_array, g_object_ref (header));
1296 g_object_unref (header);
1297 tny_iterator_next (new_headers_iter);
1299 g_object_unref (new_headers_iter);
1300 tny_folder_remove_observer (inbox, info->inbox_observer);
1301 g_object_unref (info->inbox_observer);
1302 info->inbox_observer = NULL;
1304 /* Update the last updated key, even if we don't have to get new headers */
1305 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1307 if (new_headers_array->len == 0)
1310 /* Get per-account message amount retrieval limit */
1311 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1312 if (retrieve_limit == 0)
1313 retrieve_limit = G_MAXINT;
1315 /* Get per-account retrieval type */
1316 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1317 headers_only = !g_ascii_strcasecmp (retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_HEADERS_ONLY);
1318 g_free (retrieve_type);
1321 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1323 /* TODO: Ask the user, instead of just failing,
1324 * showing mail_nc_msg_count_limit_exceeded, with 'Get
1325 * all' and 'Newest only' buttons. */
1326 if (new_headers_array->len > retrieve_limit) {
1330 if (!headers_only) {
1332 const gint msg_list_size = compute_message_array_size (new_headers_array);
1335 priv->total = MIN (new_headers_array->len, retrieve_limit);
1336 while (msg_num < priv->total) {
1337 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1338 TnyFolder *folder = tny_header_get_folder (header);
1339 GetMsgInfo *msg_info;
1341 /* Create the message info */
1342 msg_info = g_slice_new0 (GetMsgInfo);
1343 msg_info->mail_op = g_object_ref (info->mail_op);
1344 msg_info->header = g_object_ref (header);
1345 msg_info->total_bytes = msg_list_size;
1347 /* Get message in an async way */
1348 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1349 get_msg_status_cb, msg_info);
1351 g_object_unref (folder);
1357 /* Copy the headers to a list and free the array */
1358 new_headers = tny_simple_list_new ();
1359 for (i=0; i < new_headers_array->len; i++) {
1360 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1361 tny_list_append (new_headers, G_OBJECT (header));
1363 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1364 g_ptr_array_free (new_headers_array, FALSE);
1371 /* Get the transport account */
1372 transport_account = (TnyTransportAccount *)
1373 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1374 info->account_name);
1377 send_queue = modest_runtime_get_send_queue (transport_account);
1378 modest_tny_send_queue_try_to_send (send_queue);
1380 /* Check if the operation was a success */
1382 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1384 /* Set the account back to not busy */
1385 modest_account_mgr_set_account_busy (mgr, info->account_name, FALSE);
1387 /* Call the user callback */
1389 info->callback (info->mail_op, new_headers, info->user_data);
1391 /* Notify about operation end */
1392 modest_mail_operation_notify_end (info->mail_op);
1396 g_object_unref (new_headers);
1397 destroy_update_account_info (info);
1401 recurse_folders_async_cb (TnyFolderStore *folder_store,
1407 UpdateAccountInfo *info;
1408 ModestMailOperationPrivate *priv;
1410 info = (UpdateAccountInfo *) user_data;
1411 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1413 if (err || canceled) {
1414 /* Try to continue anyway */
1416 TnyIterator *iter = tny_list_create_iterator (list);
1417 while (!tny_iterator_is_done (iter)) {
1418 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1419 TnyList *folders = tny_simple_list_new ();
1421 /* Add to the list of all folders */
1422 tny_list_append (info->folders, (GObject *) folder);
1424 /* Add pending call */
1425 info->pending_calls++;
1427 tny_folder_store_get_folders_async (folder, folders, recurse_folders_async_cb,
1430 g_object_unref (G_OBJECT (folder));
1432 tny_iterator_next (iter);
1434 g_object_unref (G_OBJECT (iter));
1435 g_object_unref (G_OBJECT (list));
1438 /* Remove my own pending call */
1439 info->pending_calls--;
1441 /* This means that we have all the folders */
1442 if (info->pending_calls == 0) {
1443 TnyIterator *iter_all_folders;
1444 TnyFolder *inbox = NULL;
1446 iter_all_folders = tny_list_create_iterator (info->folders);
1448 /* Do a poke status over all folders */
1449 while (!tny_iterator_is_done (iter_all_folders) &&
1450 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1451 TnyFolder *folder = NULL;
1453 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1455 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1456 /* Get a reference to the INBOX */
1457 inbox = g_object_ref (folder);
1459 /* Issue a poke status over the folder */
1461 tny_folder_poke_status (folder);
1464 /* Free and go to next */
1465 g_object_unref (folder);
1466 tny_iterator_next (iter_all_folders);
1468 g_object_unref (iter_all_folders);
1470 /* Stop the progress notification */
1471 g_source_remove (info->update_timeout);
1472 info->update_timeout = 0;
1474 /* Refresh the INBOX */
1476 /* Refresh the folder. Our observer receives
1477 * the new emails during folder refreshes, so
1478 * we can use observer->new_headers
1480 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1481 tny_folder_add_observer (inbox, info->inbox_observer);
1483 /* Refresh the INBOX */
1484 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1485 g_object_unref (inbox);
1487 /* We could not perform the inbox refresh but
1488 we'll try to send mails anyway */
1489 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1495 * Issues the "progress-changed" signal. The timer won't be removed,
1496 * so you must call g_source_remove to stop the signal emission
1499 timeout_notify_progress (gpointer data)
1501 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1502 ModestMailOperationState *state;
1504 state = modest_mail_operation_clone_state (mail_op);
1506 /* This is a GDK lock because we are an idle callback and
1507 * the handlers of this signal can contain Gtk+ code */
1509 gdk_threads_enter (); /* CHECKED */
1510 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1511 gdk_threads_leave (); /* CHECKED */
1513 g_slice_free (ModestMailOperationState, state);
1519 modest_mail_operation_update_account (ModestMailOperation *self,
1520 const gchar *account_name,
1522 UpdateAccountCallback callback,
1525 UpdateAccountInfo *info = NULL;
1526 ModestMailOperationPrivate *priv = NULL;
1527 ModestTnyAccountStore *account_store = NULL;
1528 TnyStoreAccount *store_account = NULL;
1531 /* Init mail operation */
1532 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1535 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1536 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1538 /* Get the store account */
1539 account_store = modest_runtime_get_account_store ();
1540 store_account = (TnyStoreAccount *)
1541 modest_tny_account_store_get_server_account (account_store,
1543 TNY_ACCOUNT_TYPE_STORE);
1544 priv->account = g_object_ref (store_account);
1546 /* Create the helper object */
1547 info = g_slice_new0 (UpdateAccountInfo);
1548 info->pending_calls = 1;
1549 info->folders = tny_simple_list_new ();
1550 info->mail_op = g_object_ref (self);
1551 info->poke_all = poke_all;
1552 info->account_name = g_strdup (account_name);
1553 info->callback = callback;
1554 info->user_data = user_data;
1555 info->update_timeout = g_timeout_add (250, timeout_notify_progress, self);
1557 /* Set account busy */
1558 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1559 modest_mail_operation_notify_start (self);
1561 /* Get all folders and continue in the callback */
1562 folders = tny_simple_list_new ();
1563 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (store_account),
1564 folders, recurse_folders_async_cb,
1569 * Used to notify the queue from the main
1570 * loop. We call it inside an idle call to achieve that
1573 idle_notify_queue (gpointer data)
1575 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1577 gdk_threads_enter ();
1578 modest_mail_operation_notify_end (mail_op);
1579 gdk_threads_leave ();
1580 g_object_unref (mail_op);
1586 compare_headers_by_date (gconstpointer a,
1589 TnyHeader **header1, **header2;
1590 time_t sent1, sent2;
1592 header1 = (TnyHeader **) a;
1593 header2 = (TnyHeader **) b;
1595 sent1 = tny_header_get_date_sent (*header1);
1596 sent2 = tny_header_get_date_sent (*header2);
1598 /* We want the most recent ones (greater time_t) at the
1607 /* ******************************************************************* */
1608 /* ************************** STORE ACTIONS ************************* */
1609 /* ******************************************************************* */
1613 modest_mail_operation_create_folder (ModestMailOperation *self,
1614 TnyFolderStore *parent,
1617 ModestMailOperationPrivate *priv;
1618 TnyFolder *new_folder = NULL;
1620 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1621 g_return_val_if_fail (name, NULL);
1623 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1624 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1625 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1626 g_object_ref (parent) :
1627 modest_tny_folder_get_account (TNY_FOLDER (parent));
1629 /* Check for already existing folder */
1630 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1631 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1632 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1633 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1634 _CS("ckdg_ib_folder_already_exists"));
1638 if (TNY_IS_FOLDER (parent)) {
1639 /* Check folder rules */
1640 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1641 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1642 /* Set status failed and set an error */
1643 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1644 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1645 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1646 _("mail_in_ui_folder_create_error"));
1650 if (!strcmp (name, " ") || strchr (name, '/')) {
1651 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1652 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1653 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1654 _("mail_in_ui_folder_create_error"));
1658 /* Create the folder */
1659 modest_mail_operation_notify_start (self);
1660 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1661 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1663 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1666 /* Notify about operation end */
1667 modest_mail_operation_notify_end (self);
1673 modest_mail_operation_remove_folder (ModestMailOperation *self,
1675 gboolean remove_to_trash)
1677 TnyAccount *account;
1678 ModestMailOperationPrivate *priv;
1679 ModestTnyFolderRules rules;
1681 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1682 g_return_if_fail (TNY_IS_FOLDER (folder));
1684 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1686 /* Check folder rules */
1687 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1688 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1689 /* Set status failed and set an error */
1690 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1691 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1692 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1693 _("mail_in_ui_folder_delete_error"));
1697 /* Get the account */
1698 account = modest_tny_folder_get_account (folder);
1699 priv->account = g_object_ref(account);
1700 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1702 /* Delete folder or move to trash */
1703 if (remove_to_trash) {
1704 TnyFolder *trash_folder = NULL;
1705 trash_folder = modest_tny_account_get_special_folder (account,
1706 TNY_FOLDER_TYPE_TRASH);
1707 /* TODO: error_handling */
1709 modest_mail_operation_notify_start (self);
1710 modest_mail_operation_xfer_folder (self, folder,
1711 TNY_FOLDER_STORE (trash_folder),
1713 g_object_unref (trash_folder);
1716 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1718 modest_mail_operation_notify_start (self);
1719 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1720 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1723 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1725 g_object_unref (parent);
1727 g_warning ("%s: could not get parent folder", __FUNCTION__);
1729 g_object_unref (G_OBJECT (account));
1732 /* Notify about operation end */
1733 modest_mail_operation_notify_end (self);
1737 transfer_folder_status_cb (GObject *obj,
1741 ModestMailOperation *self;
1742 ModestMailOperationPrivate *priv;
1743 ModestMailOperationState *state;
1744 XFerMsgAsyncHelper *helper;
1746 g_return_if_fail (status != NULL);
1747 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1749 helper = (XFerMsgAsyncHelper *) user_data;
1750 g_return_if_fail (helper != NULL);
1752 self = helper->mail_op;
1753 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1755 priv->done = status->position;
1756 priv->total = status->of_total;
1758 state = modest_mail_operation_clone_state (self);
1760 /* This is not a GDK lock because we are a Tinymail callback
1761 * which is already GDK locked by Tinymail */
1763 /* no gdk_threads_enter (), CHECKED */
1765 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1767 /* no gdk_threads_leave (), CHECKED */
1769 g_slice_free (ModestMailOperationState, state);
1774 transfer_folder_cb (TnyFolder *folder,
1776 TnyFolderStore *into,
1777 TnyFolder *new_folder,
1781 XFerMsgAsyncHelper *helper;
1782 ModestMailOperation *self = NULL;
1783 ModestMailOperationPrivate *priv = NULL;
1785 helper = (XFerMsgAsyncHelper *) user_data;
1786 g_return_if_fail (helper != NULL);
1788 self = helper->mail_op;
1789 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1792 priv->error = g_error_copy (err);
1794 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1795 } else if (cancelled) {
1796 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1797 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1798 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1799 _("Transference of %s was cancelled."),
1800 tny_folder_get_name (folder));
1803 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1806 /* Notify about operation end */
1807 modest_mail_operation_notify_end (self);
1809 /* If user defined callback function was defined, call it */
1810 if (helper->user_callback) {
1812 /* This is not a GDK lock because we are a Tinymail callback
1813 * which is already GDK locked by Tinymail */
1815 /* no gdk_threads_enter (), CHECKED */
1816 helper->user_callback (self, helper->user_data);
1817 /* no gdk_threads_leave () , CHECKED */
1821 g_object_unref (helper->mail_op);
1822 g_slice_free (XFerMsgAsyncHelper, helper);
1827 * This function checks if the new name is a valid name for our local
1828 * folders account. The new name could not be the same than then name
1829 * of any of the mandatory local folders
1831 * We can not rely on tinymail because tinymail does not check the
1832 * name of the virtual folders that the account could have in the case
1833 * that we're doing a rename (because it directly calls Camel which
1834 * knows nothing about our virtual folders).
1836 * In the case of an actual copy/move (i.e. move/copy a folder between
1837 * accounts) tinymail uses the tny_folder_store_create_account which
1838 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1839 * checks the new name of the folder, so this call in that case
1840 * wouldn't be needed. *But* NOTE that if tinymail changes its
1841 * implementation (if folder transfers within the same account is no
1842 * longer implemented as a rename) this call will allow Modest to work
1845 * If the new name is not valid, this function will set the status to
1846 * failed and will set also an error in the mail operation
1849 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1850 TnyFolderStore *into,
1851 const gchar *new_name)
1853 if (TNY_IS_ACCOUNT (into) &&
1854 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1855 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1857 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1858 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1859 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1860 _CS("ckdg_ib_folder_already_exists"));
1867 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1869 TnyFolderStore *parent,
1870 gboolean delete_original,
1871 XferAsyncUserCallback user_callback,
1874 ModestMailOperationPrivate *priv = NULL;
1875 ModestTnyFolderRules parent_rules = 0, rules;
1876 XFerMsgAsyncHelper *helper = NULL;
1877 const gchar *folder_name = NULL;
1878 const gchar *error_msg;
1880 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1881 g_return_if_fail (TNY_IS_FOLDER (folder));
1882 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1884 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1885 folder_name = tny_folder_get_name (folder);
1887 /* Set the error msg */
1888 error_msg = _("mail_in_ui_folder_move_target_error");
1890 /* Get account and set it into mail_operation */
1891 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1892 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1893 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1895 /* Get folder rules */
1896 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1897 if (TNY_IS_FOLDER (parent))
1898 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1900 /* Apply operation constraints */
1901 if ((gpointer) parent == (gpointer) folder ||
1902 (!TNY_IS_FOLDER_STORE (parent)) ||
1903 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1906 } else if (TNY_IS_FOLDER (parent) &&
1907 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1911 } else if (TNY_IS_FOLDER (parent) &&
1912 TNY_IS_FOLDER_STORE (folder) &&
1913 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1914 TNY_FOLDER_STORE (folder))) {
1915 /* Do not move a parent into a child */
1917 } else if (TNY_IS_FOLDER_STORE (parent) &&
1918 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
1919 /* Check that the new folder name is not used by any
1922 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1923 /* Check that the new folder name is not used by any
1924 special local folder */
1927 /* Create the helper */
1928 helper = g_slice_new0 (XFerMsgAsyncHelper);
1929 helper->mail_op = g_object_ref (self);
1930 helper->dest_folder = NULL;
1931 helper->headers = NULL;
1932 helper->user_callback = user_callback;
1933 helper->user_data = user_data;
1935 /* Move/Copy folder */
1936 modest_mail_operation_notify_start (self);
1937 tny_folder_copy_async (folder,
1939 tny_folder_get_name (folder),
1942 transfer_folder_status_cb,
1948 /* Set status failed and set an error */
1949 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1950 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1951 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1954 /* Call the user callback if exists */
1956 user_callback (self, user_data);
1958 /* Notify the queue */
1959 modest_mail_operation_notify_end (self);
1963 modest_mail_operation_rename_folder (ModestMailOperation *self,
1967 ModestMailOperationPrivate *priv;
1968 ModestTnyFolderRules rules;
1969 XFerMsgAsyncHelper *helper;
1971 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1972 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1973 g_return_if_fail (name);
1975 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1977 /* Get account and set it into mail_operation */
1978 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1979 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1981 /* Check folder rules */
1982 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1983 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1984 /* Set status failed and set an error */
1985 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1986 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1987 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1988 _("FIXME: unable to rename"));
1990 /* Notify about operation end */
1991 modest_mail_operation_notify_end (self);
1992 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1993 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1994 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1995 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1996 _("FIXME: unable to rename"));
1997 /* Notify about operation end */
1998 modest_mail_operation_notify_end (self);
2000 TnyFolderStore *into;
2002 into = tny_folder_get_folder_store (folder);
2004 /* Check that the new folder name is not used by any
2005 special local folder */
2006 if (new_name_valid_if_local_account (priv, into, name)) {
2007 /* Create the helper */
2008 helper = g_slice_new0 (XFerMsgAsyncHelper);
2009 helper->mail_op = g_object_ref(self);
2010 helper->dest_folder = NULL;
2011 helper->headers = NULL;
2012 helper->user_callback = NULL;
2013 helper->user_data = NULL;
2015 /* Rename. Camel handles folder subscription/unsubscription */
2016 modest_mail_operation_notify_start (self);
2017 tny_folder_copy_async (folder, into, name, TRUE,
2019 transfer_folder_status_cb,
2022 modest_mail_operation_notify_end (self);
2024 g_object_unref (into);
2028 /* ******************************************************************* */
2029 /* ************************** MSG ACTIONS ************************* */
2030 /* ******************************************************************* */
2033 modest_mail_operation_get_msg (ModestMailOperation *self,
2035 GetMsgAsyncUserCallback user_callback,
2038 GetMsgInfo *helper = NULL;
2040 ModestMailOperationPrivate *priv;
2042 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2043 g_return_if_fail (TNY_IS_HEADER (header));
2045 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2046 folder = tny_header_get_folder (header);
2048 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2052 /* Get account and set it into mail_operation */
2053 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2055 /* Check for cached messages */
2056 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2057 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2059 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2061 /* Create the helper */
2062 helper = g_slice_new0 (GetMsgInfo);
2063 helper->header = g_object_ref (header);
2064 helper->mail_op = g_object_ref (self);
2065 helper->user_callback = user_callback;
2066 helper->user_data = user_data;
2067 helper->destroy_notify = NULL;
2068 helper->last_total_bytes = 0;
2069 helper->sum_total_bytes = 0;
2070 helper->total_bytes = tny_header_get_message_size (header);
2072 modest_mail_operation_notify_start (self);
2073 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2075 g_object_unref (G_OBJECT (folder));
2079 get_msg_status_cb (GObject *obj,
2083 GetMsgInfo *helper = NULL;
2085 g_return_if_fail (status != NULL);
2086 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2088 helper = (GetMsgInfo *) user_data;
2089 g_return_if_fail (helper != NULL);
2091 /* Notify progress */
2092 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2093 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2097 get_msg_async_cb (TnyFolder *folder,
2103 GetMsgInfo *info = NULL;
2104 ModestMailOperationPrivate *priv = NULL;
2107 info = (GetMsgInfo *) user_data;
2109 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2111 finished = (priv->done == priv->total) ? TRUE : FALSE;
2114 if (canceled || err) {
2115 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2117 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2118 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2121 /* Set the success status before calling the user callback */
2122 if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2123 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2127 /* Call the user callback */
2128 if (info->user_callback)
2129 info->user_callback (info->mail_op, info->header, canceled,
2130 msg, err, info->user_data);
2132 /* Notify about operation end if this is the last callback */
2134 /* Free user data */
2135 if (info->destroy_notify)
2136 info->destroy_notify (info->user_data);
2138 /* Notify about operation end */
2139 modest_mail_operation_notify_end (info->mail_op);
2143 g_object_unref (info->header);
2144 g_object_unref (info->mail_op);
2145 g_slice_free (GetMsgInfo, info);
2149 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2150 TnyList *header_list,
2151 GetMsgAsyncUserCallback user_callback,
2153 GDestroyNotify notify)
2155 ModestMailOperationPrivate *priv = NULL;
2156 gboolean size_ok = TRUE;
2158 TnyIterator *iter = NULL;
2160 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2162 /* Init mail operation */
2163 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2164 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2165 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2167 priv->total = tny_list_get_length(header_list);
2169 /* Get account and set it into mail_operation */
2170 if (tny_list_get_length (header_list) >= 1) {
2171 iter = tny_list_create_iterator (header_list);
2172 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2174 TnyFolder *folder = tny_header_get_folder (header);
2176 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2177 g_object_unref (folder);
2179 g_object_unref (header);
2182 if (tny_list_get_length (header_list) == 1) {
2183 g_object_unref (iter);
2188 /* Get msg size limit */
2189 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2190 MODEST_CONF_MSG_SIZE_LIMIT,
2193 g_clear_error (&(priv->error));
2194 max_size = G_MAXINT;
2196 max_size = max_size * KB;
2199 /* Check message size limits. If there is only one message
2200 always retrieve it */
2202 while (!tny_iterator_is_done (iter) && size_ok) {
2203 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2205 if (tny_header_get_message_size (header) >= max_size)
2207 g_object_unref (header);
2210 tny_iterator_next (iter);
2212 g_object_unref (iter);
2216 const gint msg_list_size = compute_message_list_size (header_list);
2218 modest_mail_operation_notify_start (self);
2219 iter = tny_list_create_iterator (header_list);
2220 while (!tny_iterator_is_done (iter)) {
2221 GetMsgInfo *msg_info = NULL;
2222 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2223 TnyFolder *folder = tny_header_get_folder (header);
2225 /* Create the message info */
2226 msg_info = g_slice_new0 (GetMsgInfo);
2227 msg_info->mail_op = g_object_ref (self);
2228 msg_info->header = g_object_ref (header);
2229 msg_info->user_callback = user_callback;
2230 msg_info->user_data = user_data;
2231 msg_info->destroy_notify = notify;
2232 msg_info->last_total_bytes = 0;
2233 msg_info->sum_total_bytes = 0;
2234 msg_info->total_bytes = msg_list_size;
2236 /* The callback will call it per each header */
2237 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2239 /* Free and go on */
2240 g_object_unref (header);
2241 g_object_unref (folder);
2242 tny_iterator_next (iter);
2244 g_object_unref (iter);
2246 /* Set status failed and set an error */
2247 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2248 /* FIXME: the error msg is different for pop */
2249 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2250 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2251 _("emev_ni_ui_imap_msg_size_exceed_error"));
2252 /* Remove from queue and free resources */
2253 modest_mail_operation_notify_end (self);
2261 modest_mail_operation_remove_msg (ModestMailOperation *self,
2263 gboolean remove_to_trash /*ignored*/)
2266 ModestMailOperationPrivate *priv;
2268 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2269 g_return_if_fail (TNY_IS_HEADER (header));
2271 if (remove_to_trash)
2272 g_warning ("remove to trash is not implemented");
2274 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2275 folder = tny_header_get_folder (header);
2277 /* Get account and set it into mail_operation */
2278 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2279 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2280 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2282 /* remove message from folder */
2283 tny_folder_remove_msg (folder, header, &(priv->error));
2285 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2286 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2288 modest_mail_operation_notify_start (self);
2290 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2291 TNY_IS_CAMEL_POP_FOLDER (folder))
2292 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> dont expunge */
2294 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2300 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2302 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2305 g_object_unref (G_OBJECT (folder));
2307 /* Notify about operation end */
2308 modest_mail_operation_notify_end (self);
2312 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2314 gboolean remove_to_trash /*ignored*/)
2317 ModestMailOperationPrivate *priv;
2318 TnyIterator *iter = NULL;
2319 TnyHeader *header = NULL;
2320 TnyList *remove_headers = NULL;
2321 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2323 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2324 g_return_if_fail (TNY_IS_LIST (headers));
2326 if (remove_to_trash)
2327 g_warning ("remove to trash is not implemented");
2329 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2331 remove_headers = g_object_ref(headers);
2333 /* Get folder from first header and sync it */
2334 iter = tny_list_create_iterator (headers);
2335 header = TNY_HEADER (tny_iterator_get_current (iter));
2336 folder = tny_header_get_folder (header);
2338 /* Don't remove messages that are being sent */
2339 if (modest_tny_folder_is_local_folder (folder)) {
2340 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2342 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2343 TnyTransportAccount *traccount = NULL;
2344 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2345 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2347 ModestTnySendQueueStatus status;
2348 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2349 TnyIterator *iter = tny_list_create_iterator(headers);
2350 g_object_unref(remove_headers);
2351 remove_headers = TNY_LIST(tny_simple_list_new());
2352 while (!tny_iterator_is_done(iter)) {
2354 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2355 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2356 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2357 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2358 tny_list_append(remove_headers, G_OBJECT(hdr));
2360 g_object_unref(hdr);
2362 tny_iterator_next(iter);
2364 g_object_unref(iter);
2365 g_object_unref(traccount);
2369 /* Get account and set it into mail_operation */
2370 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2371 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2372 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2374 /* remove message from folder */
2375 modest_mail_operation_notify_start (self);
2377 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2379 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2380 TNY_IS_CAMEL_POP_FOLDER (folder))
2381 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> don't expunge */
2384 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2390 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2392 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2395 g_object_unref (remove_headers);
2396 g_object_unref (header);
2397 g_object_unref (iter);
2398 g_object_unref (G_OBJECT (folder));
2400 /* Notify about operation end */
2401 modest_mail_operation_notify_end (self);
2405 notify_progress_of_multiple_messages (ModestMailOperation *self,
2407 gint *last_total_bytes,
2408 gint *sum_total_bytes,
2410 gboolean increment_done)
2412 ModestMailOperationPrivate *priv;
2413 ModestMailOperationState *state;
2414 gboolean is_num_bytes;
2416 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2418 /* We know that tinymail sends us information about
2419 transferred bytes with this particular message */
2420 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2422 state = modest_mail_operation_clone_state (self);
2423 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2424 /* We know that we're in a different message when the
2425 total number of bytes to transfer is different. Of
2426 course it could fail if we're transferring messages
2427 of the same size, but this is a workarround */
2428 if (status->of_total != *last_total_bytes) {
2429 /* We need to increment the done when there is
2430 no information about each individual
2431 message, we need to do this in message
2432 transfers, and we don't do it for getting
2436 *sum_total_bytes += *last_total_bytes;
2437 *last_total_bytes = status->of_total;
2439 state->bytes_done += status->position + *sum_total_bytes;
2440 state->bytes_total = total_bytes;
2442 /* Notify the status change. Only notify about changes
2443 referred to bytes */
2444 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2448 g_slice_free (ModestMailOperationState, state);
2452 transfer_msgs_status_cb (GObject *obj,
2456 XFerMsgAsyncHelper *helper;
2458 g_return_if_fail (status != NULL);
2459 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2461 helper = (XFerMsgAsyncHelper *) user_data;
2462 g_return_if_fail (helper != NULL);
2464 /* Notify progress */
2465 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2466 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2471 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2473 XFerMsgAsyncHelper *helper;
2474 ModestMailOperation *self;
2475 ModestMailOperationPrivate *priv;
2476 TnyIterator *iter = NULL;
2477 TnyHeader *header = NULL;
2479 helper = (XFerMsgAsyncHelper *) user_data;
2480 self = helper->mail_op;
2482 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2485 priv->error = g_error_copy (err);
2487 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2488 } else if (cancelled) {
2489 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2490 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2491 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2492 _("Error trying to refresh the contents of %s"),
2493 tny_folder_get_name (folder));
2496 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2498 /* Update folder counts */
2499 tny_folder_poke_status (folder);
2500 tny_folder_poke_status (helper->dest_folder);
2504 /* Mark headers as deleted and seen */
2505 if ((helper->delete) &&
2506 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2507 iter = tny_list_create_iterator (helper->headers);
2508 while (!tny_iterator_is_done (iter)) {
2509 header = TNY_HEADER (tny_iterator_get_current (iter));
2510 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2511 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2512 g_object_unref (header);
2514 tny_iterator_next (iter);
2520 /* Notify about operation end */
2521 modest_mail_operation_notify_end (self);
2523 /* If user defined callback function was defined, call it */
2524 if (helper->user_callback) {
2525 /* This is not a GDK lock because we are a Tinymail callback and
2526 * Tinymail already acquires the Gdk lock */
2528 /* no gdk_threads_enter (), CHECKED */
2529 helper->user_callback (self, helper->user_data);
2530 /* no gdk_threads_leave (), CHECKED */
2534 if (helper->headers)
2535 g_object_unref (helper->headers);
2536 if (helper->dest_folder)
2537 g_object_unref (helper->dest_folder);
2538 if (helper->mail_op)
2539 g_object_unref (helper->mail_op);
2541 g_object_unref (folder);
2543 g_object_unref (iter);
2544 g_slice_free (XFerMsgAsyncHelper, helper);
2548 compute_message_list_size (TnyList *headers)
2553 iter = tny_list_create_iterator (headers);
2554 while (!tny_iterator_is_done (iter)) {
2555 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2556 size += tny_header_get_message_size (header);
2557 g_object_unref (header);
2558 tny_iterator_next (iter);
2560 g_object_unref (iter);
2566 compute_message_array_size (GPtrArray *headers)
2571 for (i = 0; i < headers->len; i++) {
2572 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2573 size += tny_header_get_message_size (header);
2581 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2584 gboolean delete_original,
2585 XferAsyncUserCallback user_callback,
2588 ModestMailOperationPrivate *priv = NULL;
2589 TnyIterator *iter = NULL;
2590 TnyFolder *src_folder = NULL;
2591 XFerMsgAsyncHelper *helper = NULL;
2592 TnyHeader *header = NULL;
2593 ModestTnyFolderRules rules = 0;
2595 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2596 g_return_if_fail (headers && TNY_IS_LIST (headers));
2597 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2599 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2600 priv->total = tny_list_get_length (headers);
2602 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2603 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2605 /* Apply folder rules */
2606 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2607 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2608 /* Set status failed and set an error */
2609 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2610 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2611 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2612 _CS("ckct_ib_unable_to_paste_here"));
2613 /* Notify the queue */
2614 modest_mail_operation_notify_end (self);
2618 /* Get source folder */
2619 iter = tny_list_create_iterator (headers);
2620 header = TNY_HEADER (tny_iterator_get_current (iter));
2622 src_folder = tny_header_get_folder (header);
2623 g_object_unref (header);
2625 g_object_unref (iter);
2627 if (src_folder == NULL) {
2628 /* Notify the queue */
2629 modest_mail_operation_notify_end (self);
2631 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2636 /* Check folder source and destination */
2637 if (src_folder == folder) {
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_BAD_PARAMETER,
2642 _("mail_in_ui_folder_copy_target_error"));
2644 /* Notify the queue */
2645 modest_mail_operation_notify_end (self);
2648 g_object_unref (src_folder);
2652 /* Create the helper */
2653 helper = g_slice_new0 (XFerMsgAsyncHelper);
2654 helper->mail_op = g_object_ref(self);
2655 helper->dest_folder = g_object_ref(folder);
2656 helper->headers = g_object_ref(headers);
2657 helper->user_callback = user_callback;
2658 helper->user_data = user_data;
2659 helper->delete = delete_original;
2660 helper->last_total_bytes = 0;
2661 helper->sum_total_bytes = 0;
2662 helper->total_bytes = compute_message_list_size (headers);
2664 /* Get account and set it into mail_operation */
2665 priv->account = modest_tny_folder_get_account (src_folder);
2667 /* Transfer messages */
2668 modest_mail_operation_notify_start (self);
2669 tny_folder_transfer_msgs_async (src_folder,
2674 transfer_msgs_status_cb,
2680 on_refresh_folder (TnyFolder *folder,
2685 RefreshAsyncHelper *helper = NULL;
2686 ModestMailOperation *self = NULL;
2687 ModestMailOperationPrivate *priv = NULL;
2689 helper = (RefreshAsyncHelper *) user_data;
2690 self = helper->mail_op;
2691 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2693 g_return_if_fail(priv!=NULL);
2696 priv->error = g_error_copy (error);
2697 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2702 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2703 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2704 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2705 _("Error trying to refresh the contents of %s"),
2706 tny_folder_get_name (folder));
2710 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2713 /* Call user defined callback, if it exists */
2714 if (helper->user_callback) {
2716 /* This is not a GDK lock because we are a Tinymail callback and
2717 * Tinymail already acquires the Gdk lock */
2718 helper->user_callback (self, folder, helper->user_data);
2722 g_slice_free (RefreshAsyncHelper, helper);
2724 /* Notify about operation end */
2725 modest_mail_operation_notify_end (self);
2726 g_object_unref(self);
2730 on_refresh_folder_status_update (GObject *obj,
2734 RefreshAsyncHelper *helper = NULL;
2735 ModestMailOperation *self = NULL;
2736 ModestMailOperationPrivate *priv = NULL;
2737 ModestMailOperationState *state;
2739 g_return_if_fail (user_data != NULL);
2740 g_return_if_fail (status != NULL);
2741 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2743 helper = (RefreshAsyncHelper *) user_data;
2744 self = helper->mail_op;
2745 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2747 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2749 priv->done = status->position;
2750 priv->total = status->of_total;
2752 state = modest_mail_operation_clone_state (self);
2754 /* This is not a GDK lock because we are a Tinymail callback and
2755 * Tinymail already acquires the Gdk lock */
2756 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2758 g_slice_free (ModestMailOperationState, state);
2762 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2764 RefreshAsyncUserCallback user_callback,
2767 ModestMailOperationPrivate *priv = NULL;
2768 RefreshAsyncHelper *helper = NULL;
2770 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2772 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2774 /* Get account and set it into mail_operation */
2775 priv->account = modest_tny_folder_get_account (folder);
2776 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2778 /* Create the helper */
2779 helper = g_slice_new0 (RefreshAsyncHelper);
2780 helper->mail_op = g_object_ref(self);
2781 helper->user_callback = user_callback;
2782 helper->user_data = user_data;
2784 /* Refresh the folder. TODO: tinymail could issue a status
2785 updates before the callback call then this could happen. We
2786 must review the design */
2787 modest_mail_operation_notify_start (self);
2788 tny_folder_refresh_async (folder,
2790 on_refresh_folder_status_update,
2796 modest_mail_operation_notify_start (ModestMailOperation *self)
2798 ModestMailOperationPrivate *priv = NULL;
2800 g_return_if_fail (self);
2802 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2804 /* Ensure that all the fields are filled correctly */
2805 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
2807 /* Notify the observers about the mail operation. We do not
2808 wrapp this emission because we assume that this function is
2809 always called from within the main lock */
2810 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
2815 * It's used by the mail operation queue to notify the observers
2816 * attached to that signal that the operation finished. We need to use
2817 * that because tinymail does not give us the progress of a given
2818 * operation when it finishes (it directly calls the operation
2822 modest_mail_operation_notify_end (ModestMailOperation *self)
2824 ModestMailOperationPrivate *priv = NULL;
2826 g_return_if_fail (self);
2828 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2830 /* Notify the observers about the mail operation end. We do
2831 not wrapp this emission because we assume that this
2832 function is always called from within the main lock */
2833 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
2835 /* Remove the error user data */
2836 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
2837 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
2841 modest_mail_operation_get_account (ModestMailOperation *self)
2843 ModestMailOperationPrivate *priv = NULL;
2845 g_return_val_if_fail (self, NULL);
2847 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2849 return (priv->account) ? g_object_ref (priv->account) : NULL;
2853 modest_mail_operation_noop (ModestMailOperation *self)
2855 ModestMailOperationPrivate *priv = NULL;
2857 g_return_if_fail (self);
2859 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2860 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2861 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2865 /* This mail operation does nothing actually */
2866 modest_mail_operation_notify_start (self);
2867 modest_mail_operation_notify_end (self);