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;
675 TnyHeader *hdr1, *hdr2;
676 hdr1 = tny_msg_get_header(msg);
677 hdr2 = tny_msg_get_header(info->msg);
679 if (!strcmp (tny_header_get_message_id(hdr1),
680 tny_header_get_message_id(hdr2))) {
681 ModestMailOperationPrivate *priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
682 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
684 common_send_mail_operation_end (queue, msg, info);
686 g_object_unref(G_OBJECT(hdr1));
687 g_object_unref(G_OBJECT(hdr2));
691 send_mail_error_happened_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
692 GError *error, gpointer userdata)
694 SendMsgInfo *info = (SendMsgInfo *) userdata;
695 TnyHeader *hdr1, *hdr2;
696 hdr1 = tny_msg_get_header(msg);
697 hdr2 = tny_msg_get_header(info->msg);
699 if (!strcmp (tny_header_get_message_id(hdr1),
700 tny_header_get_message_id(hdr2))) {
701 ModestMailOperationPrivate *priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
702 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
703 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
704 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
705 "modest: send mail failed\n");
707 common_send_mail_operation_end (queue, msg, info);
709 g_object_unref(G_OBJECT(hdr1));
710 g_object_unref(G_OBJECT(hdr2));
715 idle_create_msg_cb (gpointer idle_data)
717 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
719 /* This is a GDK lock because we are an idle callback and
720 * info->callback can contain Gtk+ code */
722 gdk_threads_enter (); /* CHECKED */
723 info->callback (info->mail_op, info->msg, info->userdata);
725 g_object_unref (info->mail_op);
727 g_object_unref (info->msg);
728 g_slice_free (CreateMsgIdleInfo, info);
729 gdk_threads_leave (); /* CHECKED */
735 create_msg_thread (gpointer thread_data)
737 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
738 TnyMsg *new_msg = NULL;
739 ModestMailOperationPrivate *priv;
741 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
742 if (info->html_body == NULL) {
743 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
744 info->bcc, info->subject, info->plain_body,
745 info->attachments_list);
747 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
748 info->bcc, info->subject, info->html_body,
749 info->plain_body, info->attachments_list,
756 /* Set priority flags in message */
757 header = tny_msg_get_header (new_msg);
758 tny_header_set_flag (header, info->priority_flags);
760 /* Set attachment flags in message */
761 if (info->attachments_list != NULL)
762 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
764 g_object_unref (G_OBJECT(header));
766 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
767 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
768 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
769 "modest: failed to create a new msg\n");
777 g_free (info->plain_body);
778 g_free (info->html_body);
779 g_free (info->subject);
780 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
781 g_list_free (info->attachments_list);
782 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
783 g_list_free (info->images_list);
785 if (info->callback) {
786 CreateMsgIdleInfo *idle_info;
787 idle_info = g_slice_new0 (CreateMsgIdleInfo);
788 idle_info->mail_op = g_object_ref (info->mail_op);
789 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
790 idle_info->callback = info->callback;
791 idle_info->userdata = info->userdata;
792 g_idle_add (idle_create_msg_cb, idle_info);
794 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
797 g_object_unref (info->mail_op);
798 g_slice_free (CreateMsgInfo, info);
803 modest_mail_operation_create_msg (ModestMailOperation *self,
804 const gchar *from, const gchar *to,
805 const gchar *cc, const gchar *bcc,
806 const gchar *subject, const gchar *plain_body,
807 const gchar *html_body,
808 const GList *attachments_list,
809 const GList *images_list,
810 TnyHeaderFlags priority_flags,
811 ModestMailOperationCreateMsgCallback callback,
814 CreateMsgInfo *info = NULL;
816 info = g_slice_new0 (CreateMsgInfo);
817 info->mail_op = g_object_ref (self);
819 info->from = g_strdup (from);
820 info->to = g_strdup (to);
821 info->cc = g_strdup (cc);
822 info->bcc = g_strdup (bcc);
823 info->subject = g_strdup (subject);
824 info->plain_body = g_strdup (plain_body);
825 info->html_body = g_strdup (html_body);
826 info->attachments_list = g_list_copy ((GList *) attachments_list);
827 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
828 info->images_list = g_list_copy ((GList *) images_list);
829 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
830 info->priority_flags = priority_flags;
832 info->callback = callback;
833 info->userdata = userdata;
835 g_thread_create (create_msg_thread, info, FALSE, NULL);
840 TnyTransportAccount *transport_account;
845 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
849 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
850 TnyFolder *draft_folder = NULL;
851 TnyFolder *outbox_folder = NULL;
859 /* Call mail operation */
860 modest_mail_operation_send_mail (self, info->transport_account, msg);
862 /* Remove old mail from its source folder */
863 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
864 TNY_FOLDER_TYPE_DRAFTS);
865 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
866 TNY_FOLDER_TYPE_OUTBOX);
867 if (info->draft_msg != NULL) {
868 TnyFolder *folder = NULL;
869 TnyFolder *src_folder = NULL;
870 TnyFolderType folder_type;
871 folder = tny_msg_get_folder (info->draft_msg);
872 if (folder == NULL) goto end;
873 folder_type = modest_tny_folder_guess_folder_type (folder);
875 if (folder_type == TNY_FOLDER_TYPE_INVALID)
876 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
878 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
879 src_folder = outbox_folder;
881 src_folder = draft_folder;
883 /* Note: This can fail (with a warning) if the message is not really already in a folder,
884 * because this function requires it to have a UID. */
885 header = tny_msg_get_header (info->draft_msg);
886 tny_folder_remove_msg (src_folder, header, NULL);
888 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
889 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
891 g_object_unref (header);
892 g_object_unref (folder);
899 g_object_unref (info->draft_msg);
901 g_object_unref (draft_folder);
903 g_object_unref (outbox_folder);
904 if (info->transport_account)
905 g_object_unref (info->transport_account);
906 g_slice_free (SendNewMailInfo, info);
910 modest_mail_operation_send_new_mail (ModestMailOperation *self,
911 TnyTransportAccount *transport_account,
913 const gchar *from, const gchar *to,
914 const gchar *cc, const gchar *bcc,
915 const gchar *subject, const gchar *plain_body,
916 const gchar *html_body,
917 const GList *attachments_list,
918 const GList *images_list,
919 TnyHeaderFlags priority_flags)
921 ModestMailOperationPrivate *priv = NULL;
922 SendNewMailInfo *info;
924 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
925 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
927 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
928 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
929 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
930 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
932 /* Check parametters */
934 /* Set status failed and set an error */
935 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
936 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
937 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
938 _("Error trying to send a mail. You need to set at least one recipient"));
941 info = g_slice_new0 (SendNewMailInfo);
942 info->transport_account = transport_account;
943 if (transport_account)
944 g_object_ref (transport_account);
945 info->draft_msg = draft_msg;
947 g_object_ref (draft_msg);
950 modest_mail_operation_notify_start (self);
951 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
952 attachments_list, images_list, priority_flags,
953 modest_mail_operation_send_new_mail_cb, info);
959 TnyTransportAccount *transport_account;
961 SaveToDraftstCallback callback;
965 ModestMailOperation *mailop;
966 } SaveToDraftsAddMsgInfo;
969 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
974 ModestMailOperationPrivate *priv = NULL;
975 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
977 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
980 g_warning ("%s: priv->error != NULL", __FUNCTION__);
981 g_error_free(priv->error);
984 priv->error = (err == NULL) ? NULL : g_error_copy(err);
986 if ((!priv->error) && (info->draft_msg != NULL)) {
987 TnyHeader *header = tny_msg_get_header (info->draft_msg);
988 TnyFolder *src_folder = tny_header_get_folder (header);
990 /* Remove the old draft */
991 tny_folder_remove_msg (src_folder, header, NULL);
993 /* Synchronize to expunge and to update the msg counts */
994 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
995 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
997 g_object_unref (G_OBJECT(header));
998 g_object_unref (G_OBJECT(src_folder));
1002 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1004 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1006 /* Call the user callback */
1008 info->callback (info->mailop, info->msg, info->user_data);
1010 if (info->transport_account)
1011 g_object_unref (G_OBJECT(info->transport_account));
1012 if (info->draft_msg)
1013 g_object_unref (G_OBJECT (info->draft_msg));
1015 g_object_unref (G_OBJECT(info->drafts));
1017 g_object_unref (G_OBJECT (info->msg));
1018 g_slice_free (SaveToDraftsAddMsgInfo, info);
1020 modest_mail_operation_notify_end (info->mailop);
1021 g_object_unref(info->mailop);
1026 TnyTransportAccount *transport_account;
1028 SaveToDraftstCallback callback;
1033 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1037 TnyFolder *drafts = NULL;
1038 ModestMailOperationPrivate *priv = NULL;
1039 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1041 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1044 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1045 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1046 "modest: failed to create a new msg\n");
1048 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1049 TNY_FOLDER_TYPE_DRAFTS);
1051 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1052 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1053 "modest: failed to create a new msg\n");
1058 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1059 cb_info->transport_account = g_object_ref(info->transport_account);
1060 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1061 cb_info->callback = info->callback;
1062 cb_info->user_data = info->user_data;
1063 cb_info->drafts = g_object_ref(drafts);
1064 cb_info->msg = g_object_ref(msg);
1065 cb_info->mailop = g_object_ref(self);
1066 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1069 /* Call the user callback */
1070 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1072 info->callback (self, msg, info->user_data);
1073 modest_mail_operation_notify_end (self);
1077 g_object_unref (G_OBJECT(drafts));
1078 if (info->draft_msg)
1079 g_object_unref (G_OBJECT (info->draft_msg));
1080 if (info->transport_account)
1081 g_object_unref (G_OBJECT(info->transport_account));
1082 g_slice_free (SaveToDraftsInfo, info);
1086 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1087 TnyTransportAccount *transport_account,
1089 const gchar *from, const gchar *to,
1090 const gchar *cc, const gchar *bcc,
1091 const gchar *subject, const gchar *plain_body,
1092 const gchar *html_body,
1093 const GList *attachments_list,
1094 const GList *images_list,
1095 TnyHeaderFlags priority_flags,
1096 SaveToDraftstCallback callback,
1099 ModestMailOperationPrivate *priv = NULL;
1100 SaveToDraftsInfo *info = NULL;
1102 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1103 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1105 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1107 /* Get account and set it into mail_operation */
1108 priv->account = g_object_ref (transport_account);
1109 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1111 info = g_slice_new0 (SaveToDraftsInfo);
1112 info->transport_account = g_object_ref (transport_account);
1113 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1114 info->callback = callback;
1115 info->user_data = user_data;
1117 modest_mail_operation_notify_start (self);
1118 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1119 attachments_list, images_list, priority_flags,
1120 modest_mail_operation_save_to_drafts_cb, info);
1125 ModestMailOperation *mail_op;
1126 TnyMimePart *mime_part;
1128 GetMimePartSizeCallback callback;
1130 } GetMimePartSizeInfo;
1132 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1133 /* We use this folder observer to track the headers that have been
1134 * added to a folder */
1137 TnyList *new_headers;
1138 } InternalFolderObserver;
1141 GObjectClass parent;
1142 } InternalFolderObserverClass;
1144 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1146 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1147 internal_folder_observer,
1149 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1153 foreach_add_item (gpointer header, gpointer user_data)
1155 tny_list_prepend (TNY_LIST (user_data),
1156 g_object_ref (G_OBJECT (header)));
1159 /* This is the method that looks for new messages in a folder */
1161 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1163 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1165 TnyFolderChangeChanged changed;
1167 changed = tny_folder_change_get_changed (change);
1169 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1172 /* Get added headers */
1173 list = tny_simple_list_new ();
1174 tny_folder_change_get_added_headers (change, list);
1176 /* Add them to the folder observer */
1177 tny_list_foreach (list, foreach_add_item,
1178 derived->new_headers);
1180 g_object_unref (G_OBJECT (list));
1185 internal_folder_observer_init (InternalFolderObserver *self)
1187 self->new_headers = tny_simple_list_new ();
1190 internal_folder_observer_finalize (GObject *object)
1192 InternalFolderObserver *self;
1194 self = (InternalFolderObserver *) object;
1195 g_object_unref (self->new_headers);
1197 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1200 tny_folder_observer_init (TnyFolderObserverIface *iface)
1202 iface->update_func = internal_folder_observer_update;
1205 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1207 GObjectClass *object_class;
1209 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1210 object_class = (GObjectClass*) klass;
1211 object_class->finalize = internal_folder_observer_finalize;
1216 ModestMailOperation *mail_op;
1217 gchar *account_name;
1218 UpdateAccountCallback callback;
1223 TnyFolderObserver *inbox_observer;
1224 guint update_timeout;
1225 } UpdateAccountInfo;
1229 destroy_update_account_info (UpdateAccountInfo *info)
1231 if (info->update_timeout) {
1232 g_source_remove (info->update_timeout);
1233 info->update_timeout = 0;
1236 g_free (info->account_name);
1237 g_object_unref (info->folders);
1238 g_object_unref (info->mail_op);
1239 g_slice_free (UpdateAccountInfo, info);
1243 update_account_get_msg_async_cb (TnyFolder *folder,
1249 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1251 /* Just delete the helper. Don't do anything with the new
1252 msg. There is also no need to check for errors */
1253 g_object_unref (msg_info->mail_op);
1254 g_object_unref (msg_info->header);
1255 g_slice_free (GetMsgInfo, msg_info);
1260 inbox_refreshed_cb (TnyFolder *inbox,
1265 UpdateAccountInfo *info;
1266 ModestMailOperationPrivate *priv;
1267 TnyIterator *new_headers_iter;
1268 GPtrArray *new_headers_array = NULL;
1269 gint max_size, retrieve_limit, i;
1270 ModestAccountMgr *mgr;
1271 ModestAccountRetrieveType retrieve_type;
1272 TnyList *new_headers = NULL;
1273 gboolean headers_only;
1274 TnyTransportAccount *transport_account;
1275 ModestTnySendQueue *send_queue;
1277 info = (UpdateAccountInfo *) user_data;
1278 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1279 mgr = modest_runtime_get_account_mgr ();
1281 if (canceled || err || !inbox) {
1282 /* Try to send anyway */
1286 /* Get the message max size */
1287 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1288 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1290 max_size = G_MAXINT;
1292 max_size = max_size * KB;
1294 /* Create the new headers array. We need it to sort the
1295 new headers by date */
1296 new_headers_array = g_ptr_array_new ();
1297 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1298 while (!tny_iterator_is_done (new_headers_iter)) {
1299 TnyHeader *header = NULL;
1301 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1302 /* Apply per-message size limits */
1303 if (tny_header_get_message_size (header) < max_size)
1304 g_ptr_array_add (new_headers_array, g_object_ref (header));
1306 g_object_unref (header);
1307 tny_iterator_next (new_headers_iter);
1309 g_object_unref (new_headers_iter);
1310 tny_folder_remove_observer (inbox, info->inbox_observer);
1311 g_object_unref (info->inbox_observer);
1312 info->inbox_observer = NULL;
1314 /* Update the last updated key, even if we don't have to get new headers */
1315 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1317 if (new_headers_array->len == 0)
1320 /* Get per-account message amount retrieval limit */
1321 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1322 if (retrieve_limit == 0)
1323 retrieve_limit = G_MAXINT;
1325 /* Get per-account retrieval type */
1326 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1327 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1330 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1332 /* TODO: Ask the user, instead of just failing,
1333 * showing mail_nc_msg_count_limit_exceeded, with 'Get
1334 * all' and 'Newest only' buttons. */
1335 if (new_headers_array->len > retrieve_limit) {
1339 if (!headers_only) {
1341 const gint msg_list_size = compute_message_array_size (new_headers_array);
1344 priv->total = MIN (new_headers_array->len, retrieve_limit);
1345 while (msg_num < priv->total) {
1346 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1347 TnyFolder *folder = tny_header_get_folder (header);
1348 GetMsgInfo *msg_info;
1350 /* Create the message info */
1351 msg_info = g_slice_new0 (GetMsgInfo);
1352 msg_info->mail_op = g_object_ref (info->mail_op);
1353 msg_info->header = g_object_ref (header);
1354 msg_info->total_bytes = msg_list_size;
1356 /* Get message in an async way */
1357 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1358 get_msg_status_cb, msg_info);
1360 g_object_unref (folder);
1366 /* Copy the headers to a list and free the array */
1367 new_headers = tny_simple_list_new ();
1368 for (i=0; i < new_headers_array->len; i++) {
1369 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1370 tny_list_append (new_headers, G_OBJECT (header));
1372 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1373 g_ptr_array_free (new_headers_array, FALSE);
1380 /* Get the transport account */
1381 transport_account = (TnyTransportAccount *)
1382 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1383 info->account_name);
1386 send_queue = modest_runtime_get_send_queue (transport_account);
1387 modest_tny_send_queue_try_to_send (send_queue);
1389 /* Check if the operation was a success */
1391 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1393 /* Set the account back to not busy */
1394 modest_account_mgr_set_account_busy (mgr, info->account_name, FALSE);
1396 /* Call the user callback */
1398 info->callback (info->mail_op, new_headers, info->user_data);
1400 /* Notify about operation end */
1401 modest_mail_operation_notify_end (info->mail_op);
1405 g_object_unref (new_headers);
1406 destroy_update_account_info (info);
1410 recurse_folders_async_cb (TnyFolderStore *folder_store,
1416 UpdateAccountInfo *info;
1417 ModestMailOperationPrivate *priv;
1419 info = (UpdateAccountInfo *) user_data;
1420 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1422 if (err || canceled) {
1423 /* Try to continue anyway */
1425 TnyIterator *iter = tny_list_create_iterator (list);
1426 while (!tny_iterator_is_done (iter)) {
1427 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1428 TnyList *folders = tny_simple_list_new ();
1430 /* Add to the list of all folders */
1431 tny_list_append (info->folders, (GObject *) folder);
1433 /* Add pending call */
1434 info->pending_calls++;
1436 tny_folder_store_get_folders_async (folder, folders, recurse_folders_async_cb,
1439 g_object_unref (G_OBJECT (folder));
1441 tny_iterator_next (iter);
1443 g_object_unref (G_OBJECT (iter));
1444 g_object_unref (G_OBJECT (list));
1447 /* Remove my own pending call */
1448 info->pending_calls--;
1450 /* This means that we have all the folders */
1451 if (info->pending_calls == 0) {
1452 TnyIterator *iter_all_folders;
1453 TnyFolder *inbox = NULL;
1455 iter_all_folders = tny_list_create_iterator (info->folders);
1457 /* Do a poke status over all folders */
1458 while (!tny_iterator_is_done (iter_all_folders) &&
1459 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1460 TnyFolder *folder = NULL;
1462 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1464 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1465 /* Get a reference to the INBOX */
1466 inbox = g_object_ref (folder);
1468 /* Issue a poke status over the folder */
1470 tny_folder_poke_status (folder);
1473 /* Free and go to next */
1474 g_object_unref (folder);
1475 tny_iterator_next (iter_all_folders);
1477 g_object_unref (iter_all_folders);
1479 /* Stop the progress notification */
1480 g_source_remove (info->update_timeout);
1481 info->update_timeout = 0;
1483 /* Refresh the INBOX */
1485 /* Refresh the folder. Our observer receives
1486 * the new emails during folder refreshes, so
1487 * we can use observer->new_headers
1489 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1490 tny_folder_add_observer (inbox, info->inbox_observer);
1492 /* Refresh the INBOX */
1493 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1494 g_object_unref (inbox);
1496 /* We could not perform the inbox refresh but
1497 we'll try to send mails anyway */
1498 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1504 * Issues the "progress-changed" signal. The timer won't be removed,
1505 * so you must call g_source_remove to stop the signal emission
1508 timeout_notify_progress (gpointer data)
1510 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1511 ModestMailOperationState *state;
1513 state = modest_mail_operation_clone_state (mail_op);
1515 /* This is a GDK lock because we are an idle callback and
1516 * the handlers of this signal can contain Gtk+ code */
1518 gdk_threads_enter (); /* CHECKED */
1519 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1520 gdk_threads_leave (); /* CHECKED */
1522 g_slice_free (ModestMailOperationState, state);
1528 modest_mail_operation_update_account (ModestMailOperation *self,
1529 const gchar *account_name,
1531 UpdateAccountCallback callback,
1534 UpdateAccountInfo *info = NULL;
1535 ModestMailOperationPrivate *priv = NULL;
1536 ModestTnyAccountStore *account_store = NULL;
1537 TnyStoreAccount *store_account = NULL;
1540 /* Init mail operation */
1541 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1544 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1545 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1547 /* Get the store account */
1548 account_store = modest_runtime_get_account_store ();
1549 store_account = (TnyStoreAccount *)
1550 modest_tny_account_store_get_server_account (account_store,
1552 TNY_ACCOUNT_TYPE_STORE);
1553 priv->account = g_object_ref (store_account);
1555 /* Create the helper object */
1556 info = g_slice_new0 (UpdateAccountInfo);
1557 info->pending_calls = 1;
1558 info->folders = tny_simple_list_new ();
1559 info->mail_op = g_object_ref (self);
1560 info->poke_all = poke_all;
1561 info->account_name = g_strdup (account_name);
1562 info->callback = callback;
1563 info->user_data = user_data;
1564 info->update_timeout = g_timeout_add (250, timeout_notify_progress, self);
1566 /* Set account busy */
1567 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1568 modest_mail_operation_notify_start (self);
1570 /* Get all folders and continue in the callback */
1571 folders = tny_simple_list_new ();
1572 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (store_account),
1573 folders, recurse_folders_async_cb,
1578 * Used to notify the queue from the main
1579 * loop. We call it inside an idle call to achieve that
1582 idle_notify_queue (gpointer data)
1584 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1586 gdk_threads_enter ();
1587 modest_mail_operation_notify_end (mail_op);
1588 gdk_threads_leave ();
1589 g_object_unref (mail_op);
1595 compare_headers_by_date (gconstpointer a,
1598 TnyHeader **header1, **header2;
1599 time_t sent1, sent2;
1601 header1 = (TnyHeader **) a;
1602 header2 = (TnyHeader **) b;
1604 sent1 = tny_header_get_date_sent (*header1);
1605 sent2 = tny_header_get_date_sent (*header2);
1607 /* We want the most recent ones (greater time_t) at the
1616 /* ******************************************************************* */
1617 /* ************************** STORE ACTIONS ************************* */
1618 /* ******************************************************************* */
1622 modest_mail_operation_create_folder (ModestMailOperation *self,
1623 TnyFolderStore *parent,
1626 ModestMailOperationPrivate *priv;
1627 TnyFolder *new_folder = NULL;
1629 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1630 g_return_val_if_fail (name, NULL);
1632 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1633 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1634 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1635 g_object_ref (parent) :
1636 modest_tny_folder_get_account (TNY_FOLDER (parent));
1638 /* Check for already existing folder */
1639 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1640 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1641 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1642 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1643 _CS("ckdg_ib_folder_already_exists"));
1647 if (TNY_IS_FOLDER (parent)) {
1648 /* Check folder rules */
1649 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1650 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1651 /* Set status failed and set an error */
1652 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1653 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1654 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1655 _("mail_in_ui_folder_create_error"));
1659 if (!strcmp (name, " ") || strchr (name, '/')) {
1660 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1661 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1662 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1663 _("mail_in_ui_folder_create_error"));
1667 /* Create the folder */
1668 modest_mail_operation_notify_start (self);
1669 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1670 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1672 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1675 /* Notify about operation end */
1676 modest_mail_operation_notify_end (self);
1682 modest_mail_operation_remove_folder (ModestMailOperation *self,
1684 gboolean remove_to_trash)
1686 TnyAccount *account;
1687 ModestMailOperationPrivate *priv;
1688 ModestTnyFolderRules rules;
1690 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1691 g_return_if_fail (TNY_IS_FOLDER (folder));
1693 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1695 /* Check folder rules */
1696 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1697 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1698 /* Set status failed and set an error */
1699 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1700 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1701 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1702 _("mail_in_ui_folder_delete_error"));
1706 /* Get the account */
1707 account = modest_tny_folder_get_account (folder);
1708 priv->account = g_object_ref(account);
1709 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1711 /* Delete folder or move to trash */
1712 if (remove_to_trash) {
1713 TnyFolder *trash_folder = NULL;
1714 trash_folder = modest_tny_account_get_special_folder (account,
1715 TNY_FOLDER_TYPE_TRASH);
1716 /* TODO: error_handling */
1718 modest_mail_operation_notify_start (self);
1719 modest_mail_operation_xfer_folder (self, folder,
1720 TNY_FOLDER_STORE (trash_folder),
1722 g_object_unref (trash_folder);
1725 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1727 modest_mail_operation_notify_start (self);
1728 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1729 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1732 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1734 g_object_unref (parent);
1736 g_warning ("%s: could not get parent folder", __FUNCTION__);
1738 g_object_unref (G_OBJECT (account));
1741 /* Notify about operation end */
1742 modest_mail_operation_notify_end (self);
1746 transfer_folder_status_cb (GObject *obj,
1750 ModestMailOperation *self;
1751 ModestMailOperationPrivate *priv;
1752 ModestMailOperationState *state;
1753 XFerMsgAsyncHelper *helper;
1755 g_return_if_fail (status != NULL);
1756 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1758 helper = (XFerMsgAsyncHelper *) user_data;
1759 g_return_if_fail (helper != NULL);
1761 self = helper->mail_op;
1762 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1764 priv->done = status->position;
1765 priv->total = status->of_total;
1767 state = modest_mail_operation_clone_state (self);
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 */
1774 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1776 /* no gdk_threads_leave (), CHECKED */
1778 g_slice_free (ModestMailOperationState, state);
1783 transfer_folder_cb (TnyFolder *folder,
1785 TnyFolderStore *into,
1786 TnyFolder *new_folder,
1790 XFerMsgAsyncHelper *helper;
1791 ModestMailOperation *self = NULL;
1792 ModestMailOperationPrivate *priv = NULL;
1794 helper = (XFerMsgAsyncHelper *) user_data;
1795 g_return_if_fail (helper != NULL);
1797 self = helper->mail_op;
1798 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1801 priv->error = g_error_copy (err);
1803 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1804 } else if (cancelled) {
1805 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1806 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1807 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1808 _("Transference of %s was cancelled."),
1809 tny_folder_get_name (folder));
1812 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1815 /* Notify about operation end */
1816 modest_mail_operation_notify_end (self);
1818 /* If user defined callback function was defined, call it */
1819 if (helper->user_callback) {
1821 /* This is not a GDK lock because we are a Tinymail callback
1822 * which is already GDK locked by Tinymail */
1824 /* no gdk_threads_enter (), CHECKED */
1825 helper->user_callback (self, helper->user_data);
1826 /* no gdk_threads_leave () , CHECKED */
1830 g_object_unref (helper->mail_op);
1831 g_slice_free (XFerMsgAsyncHelper, helper);
1836 * This function checks if the new name is a valid name for our local
1837 * folders account. The new name could not be the same than then name
1838 * of any of the mandatory local folders
1840 * We can not rely on tinymail because tinymail does not check the
1841 * name of the virtual folders that the account could have in the case
1842 * that we're doing a rename (because it directly calls Camel which
1843 * knows nothing about our virtual folders).
1845 * In the case of an actual copy/move (i.e. move/copy a folder between
1846 * accounts) tinymail uses the tny_folder_store_create_account which
1847 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1848 * checks the new name of the folder, so this call in that case
1849 * wouldn't be needed. *But* NOTE that if tinymail changes its
1850 * implementation (if folder transfers within the same account is no
1851 * longer implemented as a rename) this call will allow Modest to work
1854 * If the new name is not valid, this function will set the status to
1855 * failed and will set also an error in the mail operation
1858 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1859 TnyFolderStore *into,
1860 const gchar *new_name)
1862 if (TNY_IS_ACCOUNT (into) &&
1863 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1864 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1866 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1867 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1868 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1869 _CS("ckdg_ib_folder_already_exists"));
1876 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1878 TnyFolderStore *parent,
1879 gboolean delete_original,
1880 XferAsyncUserCallback user_callback,
1883 ModestMailOperationPrivate *priv = NULL;
1884 ModestTnyFolderRules parent_rules = 0, rules;
1885 XFerMsgAsyncHelper *helper = NULL;
1886 const gchar *folder_name = NULL;
1887 const gchar *error_msg;
1889 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1890 g_return_if_fail (TNY_IS_FOLDER (folder));
1891 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1893 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1894 folder_name = tny_folder_get_name (folder);
1896 /* Set the error msg */
1897 error_msg = _("mail_in_ui_folder_move_target_error");
1899 /* Get account and set it into mail_operation */
1900 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1901 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1902 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1904 /* Get folder rules */
1905 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1906 if (TNY_IS_FOLDER (parent))
1907 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1909 /* Apply operation constraints */
1910 if ((gpointer) parent == (gpointer) folder ||
1911 (!TNY_IS_FOLDER_STORE (parent)) ||
1912 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1915 } else if (TNY_IS_FOLDER (parent) &&
1916 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1920 } else if (TNY_IS_FOLDER (parent) &&
1921 TNY_IS_FOLDER_STORE (folder) &&
1922 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1923 TNY_FOLDER_STORE (folder))) {
1924 /* Do not move a parent into a child */
1926 } else if (TNY_IS_FOLDER_STORE (parent) &&
1927 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
1928 /* Check that the new folder name is not used by any
1931 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1932 /* Check that the new folder name is not used by any
1933 special local folder */
1936 /* Create the helper */
1937 helper = g_slice_new0 (XFerMsgAsyncHelper);
1938 helper->mail_op = g_object_ref (self);
1939 helper->dest_folder = NULL;
1940 helper->headers = NULL;
1941 helper->user_callback = user_callback;
1942 helper->user_data = user_data;
1944 /* Move/Copy folder */
1945 modest_mail_operation_notify_start (self);
1946 tny_folder_copy_async (folder,
1948 tny_folder_get_name (folder),
1951 transfer_folder_status_cb,
1957 /* Set status failed and set an error */
1958 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1959 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1960 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1963 /* Call the user callback if exists */
1965 user_callback (self, user_data);
1967 /* Notify the queue */
1968 modest_mail_operation_notify_end (self);
1972 modest_mail_operation_rename_folder (ModestMailOperation *self,
1976 ModestMailOperationPrivate *priv;
1977 ModestTnyFolderRules rules;
1978 XFerMsgAsyncHelper *helper;
1980 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1981 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1982 g_return_if_fail (name);
1984 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1986 /* Get account and set it into mail_operation */
1987 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1988 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1990 /* Check folder rules */
1991 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1992 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1993 /* Set status failed and set an error */
1994 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1995 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1996 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1997 _("FIXME: unable to rename"));
1999 /* Notify about operation end */
2000 modest_mail_operation_notify_end (self);
2001 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2002 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2003 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2004 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2005 _("FIXME: unable to rename"));
2006 /* Notify about operation end */
2007 modest_mail_operation_notify_end (self);
2009 TnyFolderStore *into;
2011 into = tny_folder_get_folder_store (folder);
2013 /* Check that the new folder name is not used by any
2014 special local folder */
2015 if (new_name_valid_if_local_account (priv, into, name)) {
2016 /* Create the helper */
2017 helper = g_slice_new0 (XFerMsgAsyncHelper);
2018 helper->mail_op = g_object_ref(self);
2019 helper->dest_folder = NULL;
2020 helper->headers = NULL;
2021 helper->user_callback = NULL;
2022 helper->user_data = NULL;
2024 /* Rename. Camel handles folder subscription/unsubscription */
2025 modest_mail_operation_notify_start (self);
2026 tny_folder_copy_async (folder, into, name, TRUE,
2028 transfer_folder_status_cb,
2031 modest_mail_operation_notify_end (self);
2033 g_object_unref (into);
2037 /* ******************************************************************* */
2038 /* ************************** MSG ACTIONS ************************* */
2039 /* ******************************************************************* */
2042 modest_mail_operation_get_msg (ModestMailOperation *self,
2044 GetMsgAsyncUserCallback user_callback,
2047 GetMsgInfo *helper = NULL;
2049 ModestMailOperationPrivate *priv;
2051 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2052 g_return_if_fail (TNY_IS_HEADER (header));
2054 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2055 folder = tny_header_get_folder (header);
2057 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2061 /* Get account and set it into mail_operation */
2062 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2064 /* Check for cached messages */
2065 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2066 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2068 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2070 /* Create the helper */
2071 helper = g_slice_new0 (GetMsgInfo);
2072 helper->header = g_object_ref (header);
2073 helper->mail_op = g_object_ref (self);
2074 helper->user_callback = user_callback;
2075 helper->user_data = user_data;
2076 helper->destroy_notify = NULL;
2077 helper->last_total_bytes = 0;
2078 helper->sum_total_bytes = 0;
2079 helper->total_bytes = tny_header_get_message_size (header);
2081 modest_mail_operation_notify_start (self);
2082 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2084 g_object_unref (G_OBJECT (folder));
2088 get_msg_status_cb (GObject *obj,
2092 GetMsgInfo *helper = NULL;
2094 g_return_if_fail (status != NULL);
2095 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2097 helper = (GetMsgInfo *) user_data;
2098 g_return_if_fail (helper != NULL);
2100 /* Notify progress */
2101 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2102 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2106 get_msg_async_cb (TnyFolder *folder,
2112 GetMsgInfo *info = NULL;
2113 ModestMailOperationPrivate *priv = NULL;
2116 info = (GetMsgInfo *) user_data;
2118 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2120 finished = (priv->done == priv->total) ? TRUE : FALSE;
2123 if (canceled || err) {
2124 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2126 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2127 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2130 /* Set the success status before calling the user callback */
2131 if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2132 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2136 /* Call the user callback */
2137 if (info->user_callback)
2138 info->user_callback (info->mail_op, info->header, canceled,
2139 msg, err, info->user_data);
2141 /* Notify about operation end if this is the last callback */
2143 /* Free user data */
2144 if (info->destroy_notify)
2145 info->destroy_notify (info->user_data);
2147 /* Notify about operation end */
2148 modest_mail_operation_notify_end (info->mail_op);
2152 g_object_unref (info->header);
2153 g_object_unref (info->mail_op);
2154 g_slice_free (GetMsgInfo, info);
2158 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2159 TnyList *header_list,
2160 GetMsgAsyncUserCallback user_callback,
2162 GDestroyNotify notify)
2164 ModestMailOperationPrivate *priv = NULL;
2165 gboolean size_ok = TRUE;
2167 TnyIterator *iter = NULL;
2169 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2171 /* Init mail operation */
2172 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2173 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2174 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2176 priv->total = tny_list_get_length(header_list);
2178 /* Get account and set it into mail_operation */
2179 if (tny_list_get_length (header_list) >= 1) {
2180 iter = tny_list_create_iterator (header_list);
2181 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2183 TnyFolder *folder = tny_header_get_folder (header);
2185 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2186 g_object_unref (folder);
2188 g_object_unref (header);
2191 if (tny_list_get_length (header_list) == 1) {
2192 g_object_unref (iter);
2197 /* Get msg size limit */
2198 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2199 MODEST_CONF_MSG_SIZE_LIMIT,
2202 g_clear_error (&(priv->error));
2203 max_size = G_MAXINT;
2205 max_size = max_size * KB;
2208 /* Check message size limits. If there is only one message
2209 always retrieve it */
2211 while (!tny_iterator_is_done (iter) && size_ok) {
2212 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2214 if (tny_header_get_message_size (header) >= max_size)
2216 g_object_unref (header);
2219 tny_iterator_next (iter);
2221 g_object_unref (iter);
2225 const gint msg_list_size = compute_message_list_size (header_list);
2227 modest_mail_operation_notify_start (self);
2228 iter = tny_list_create_iterator (header_list);
2229 while (!tny_iterator_is_done (iter)) {
2230 GetMsgInfo *msg_info = NULL;
2231 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2232 TnyFolder *folder = tny_header_get_folder (header);
2234 /* Create the message info */
2235 msg_info = g_slice_new0 (GetMsgInfo);
2236 msg_info->mail_op = g_object_ref (self);
2237 msg_info->header = g_object_ref (header);
2238 msg_info->user_callback = user_callback;
2239 msg_info->user_data = user_data;
2240 msg_info->destroy_notify = notify;
2241 msg_info->last_total_bytes = 0;
2242 msg_info->sum_total_bytes = 0;
2243 msg_info->total_bytes = msg_list_size;
2245 /* The callback will call it per each header */
2246 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2248 /* Free and go on */
2249 g_object_unref (header);
2250 g_object_unref (folder);
2251 tny_iterator_next (iter);
2253 g_object_unref (iter);
2255 /* Set status failed and set an error */
2256 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2257 /* FIXME: the error msg is different for pop */
2258 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2259 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2260 _("emev_ni_ui_imap_msg_size_exceed_error"));
2261 /* Remove from queue and free resources */
2262 modest_mail_operation_notify_end (self);
2270 modest_mail_operation_remove_msg (ModestMailOperation *self,
2272 gboolean remove_to_trash /*ignored*/)
2275 ModestMailOperationPrivate *priv;
2277 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2278 g_return_if_fail (TNY_IS_HEADER (header));
2280 if (remove_to_trash)
2281 g_warning ("remove to trash is not implemented");
2283 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2284 folder = tny_header_get_folder (header);
2286 /* Get account and set it into mail_operation */
2287 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2288 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2289 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2291 /* remove message from folder */
2292 tny_folder_remove_msg (folder, header, &(priv->error));
2294 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2295 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2297 modest_mail_operation_notify_start (self);
2299 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2300 TNY_IS_CAMEL_POP_FOLDER (folder))
2301 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> dont expunge */
2303 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2309 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2311 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2314 g_object_unref (G_OBJECT (folder));
2316 /* Notify about operation end */
2317 modest_mail_operation_notify_end (self);
2321 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2323 gboolean remove_to_trash /*ignored*/)
2326 ModestMailOperationPrivate *priv;
2327 TnyIterator *iter = NULL;
2328 TnyHeader *header = NULL;
2329 TnyList *remove_headers = NULL;
2330 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2332 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2333 g_return_if_fail (TNY_IS_LIST (headers));
2335 if (remove_to_trash)
2336 g_warning ("remove to trash is not implemented");
2338 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2340 remove_headers = g_object_ref(headers);
2342 /* Get folder from first header and sync it */
2343 iter = tny_list_create_iterator (headers);
2344 header = TNY_HEADER (tny_iterator_get_current (iter));
2345 folder = tny_header_get_folder (header);
2347 /* Don't remove messages that are being sent */
2348 if (modest_tny_folder_is_local_folder (folder)) {
2349 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2351 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2352 TnyTransportAccount *traccount = NULL;
2353 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2354 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2356 ModestTnySendQueueStatus status;
2357 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2358 TnyIterator *iter = tny_list_create_iterator(headers);
2359 g_object_unref(remove_headers);
2360 remove_headers = TNY_LIST(tny_simple_list_new());
2361 while (!tny_iterator_is_done(iter)) {
2363 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2364 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2365 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2366 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2367 tny_list_append(remove_headers, G_OBJECT(hdr));
2369 g_object_unref(hdr);
2371 tny_iterator_next(iter);
2373 g_object_unref(iter);
2374 g_object_unref(traccount);
2378 /* Get account and set it into mail_operation */
2379 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2380 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2381 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2383 /* remove message from folder */
2384 modest_mail_operation_notify_start (self);
2386 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2388 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2389 TNY_IS_CAMEL_POP_FOLDER (folder))
2390 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> don't expunge */
2393 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2399 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2401 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2404 g_object_unref (remove_headers);
2405 g_object_unref (header);
2406 g_object_unref (iter);
2407 g_object_unref (G_OBJECT (folder));
2409 /* Notify about operation end */
2410 modest_mail_operation_notify_end (self);
2414 notify_progress_of_multiple_messages (ModestMailOperation *self,
2416 gint *last_total_bytes,
2417 gint *sum_total_bytes,
2419 gboolean increment_done)
2421 ModestMailOperationPrivate *priv;
2422 ModestMailOperationState *state;
2423 gboolean is_num_bytes;
2425 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2427 /* We know that tinymail sends us information about
2428 transferred bytes with this particular message */
2429 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2431 state = modest_mail_operation_clone_state (self);
2432 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2433 /* We know that we're in a different message when the
2434 total number of bytes to transfer is different. Of
2435 course it could fail if we're transferring messages
2436 of the same size, but this is a workarround */
2437 if (status->of_total != *last_total_bytes) {
2438 /* We need to increment the done when there is
2439 no information about each individual
2440 message, we need to do this in message
2441 transfers, and we don't do it for getting
2445 *sum_total_bytes += *last_total_bytes;
2446 *last_total_bytes = status->of_total;
2448 state->bytes_done += status->position + *sum_total_bytes;
2449 state->bytes_total = total_bytes;
2451 /* Notify the status change. Only notify about changes
2452 referred to bytes */
2453 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2457 g_slice_free (ModestMailOperationState, state);
2461 transfer_msgs_status_cb (GObject *obj,
2465 XFerMsgAsyncHelper *helper;
2467 g_return_if_fail (status != NULL);
2468 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2470 helper = (XFerMsgAsyncHelper *) user_data;
2471 g_return_if_fail (helper != NULL);
2473 /* Notify progress */
2474 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2475 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2480 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2482 XFerMsgAsyncHelper *helper;
2483 ModestMailOperation *self;
2484 ModestMailOperationPrivate *priv;
2485 TnyIterator *iter = NULL;
2486 TnyHeader *header = NULL;
2488 helper = (XFerMsgAsyncHelper *) user_data;
2489 self = helper->mail_op;
2491 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2494 priv->error = g_error_copy (err);
2496 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2497 } else if (cancelled) {
2498 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2499 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2500 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2501 _("Error trying to refresh the contents of %s"),
2502 tny_folder_get_name (folder));
2505 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2507 /* Update folder counts */
2508 tny_folder_poke_status (folder);
2509 tny_folder_poke_status (helper->dest_folder);
2513 /* Mark headers as deleted and seen */
2514 if ((helper->delete) &&
2515 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2516 iter = tny_list_create_iterator (helper->headers);
2517 while (!tny_iterator_is_done (iter)) {
2518 header = TNY_HEADER (tny_iterator_get_current (iter));
2519 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2520 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2521 g_object_unref (header);
2523 tny_iterator_next (iter);
2529 /* Notify about operation end */
2530 modest_mail_operation_notify_end (self);
2532 /* If user defined callback function was defined, call it */
2533 if (helper->user_callback) {
2534 /* This is not a GDK lock because we are a Tinymail callback and
2535 * Tinymail already acquires the Gdk lock */
2537 /* no gdk_threads_enter (), CHECKED */
2538 helper->user_callback (self, helper->user_data);
2539 /* no gdk_threads_leave (), CHECKED */
2543 if (helper->headers)
2544 g_object_unref (helper->headers);
2545 if (helper->dest_folder)
2546 g_object_unref (helper->dest_folder);
2547 if (helper->mail_op)
2548 g_object_unref (helper->mail_op);
2550 g_object_unref (folder);
2552 g_object_unref (iter);
2553 g_slice_free (XFerMsgAsyncHelper, helper);
2557 compute_message_list_size (TnyList *headers)
2562 iter = tny_list_create_iterator (headers);
2563 while (!tny_iterator_is_done (iter)) {
2564 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2565 size += tny_header_get_message_size (header);
2566 g_object_unref (header);
2567 tny_iterator_next (iter);
2569 g_object_unref (iter);
2575 compute_message_array_size (GPtrArray *headers)
2580 for (i = 0; i < headers->len; i++) {
2581 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2582 size += tny_header_get_message_size (header);
2590 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2593 gboolean delete_original,
2594 XferAsyncUserCallback user_callback,
2597 ModestMailOperationPrivate *priv = NULL;
2598 TnyIterator *iter = NULL;
2599 TnyFolder *src_folder = NULL;
2600 XFerMsgAsyncHelper *helper = NULL;
2601 TnyHeader *header = NULL;
2602 ModestTnyFolderRules rules = 0;
2604 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2605 g_return_if_fail (headers && TNY_IS_LIST (headers));
2606 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2608 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2609 priv->total = tny_list_get_length (headers);
2611 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2612 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2614 /* Apply folder rules */
2615 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2616 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2617 /* Set status failed and set an error */
2618 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2619 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2620 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2621 _CS("ckct_ib_unable_to_paste_here"));
2622 /* Notify the queue */
2623 modest_mail_operation_notify_end (self);
2627 /* Get source folder */
2628 iter = tny_list_create_iterator (headers);
2629 header = TNY_HEADER (tny_iterator_get_current (iter));
2631 src_folder = tny_header_get_folder (header);
2632 g_object_unref (header);
2634 g_object_unref (iter);
2636 if (src_folder == NULL) {
2637 /* Notify the queue */
2638 modest_mail_operation_notify_end (self);
2640 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2645 /* Check folder source and destination */
2646 if (src_folder == folder) {
2647 /* Set status failed and set an error */
2648 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2649 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2650 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2651 _("mail_in_ui_folder_copy_target_error"));
2653 /* Notify the queue */
2654 modest_mail_operation_notify_end (self);
2657 g_object_unref (src_folder);
2661 /* Create the helper */
2662 helper = g_slice_new0 (XFerMsgAsyncHelper);
2663 helper->mail_op = g_object_ref(self);
2664 helper->dest_folder = g_object_ref(folder);
2665 helper->headers = g_object_ref(headers);
2666 helper->user_callback = user_callback;
2667 helper->user_data = user_data;
2668 helper->delete = delete_original;
2669 helper->last_total_bytes = 0;
2670 helper->sum_total_bytes = 0;
2671 helper->total_bytes = compute_message_list_size (headers);
2673 /* Get account and set it into mail_operation */
2674 priv->account = modest_tny_folder_get_account (src_folder);
2676 /* Transfer messages */
2677 modest_mail_operation_notify_start (self);
2678 tny_folder_transfer_msgs_async (src_folder,
2683 transfer_msgs_status_cb,
2689 on_refresh_folder (TnyFolder *folder,
2694 RefreshAsyncHelper *helper = NULL;
2695 ModestMailOperation *self = NULL;
2696 ModestMailOperationPrivate *priv = NULL;
2698 helper = (RefreshAsyncHelper *) user_data;
2699 self = helper->mail_op;
2700 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2702 g_return_if_fail(priv!=NULL);
2705 priv->error = g_error_copy (error);
2706 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2711 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2712 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2713 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2714 _("Error trying to refresh the contents of %s"),
2715 tny_folder_get_name (folder));
2719 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2722 /* Call user defined callback, if it exists */
2723 if (helper->user_callback) {
2725 /* This is not a GDK lock because we are a Tinymail callback and
2726 * Tinymail already acquires the Gdk lock */
2727 helper->user_callback (self, folder, helper->user_data);
2731 g_slice_free (RefreshAsyncHelper, helper);
2733 /* Notify about operation end */
2734 modest_mail_operation_notify_end (self);
2735 g_object_unref(self);
2739 on_refresh_folder_status_update (GObject *obj,
2743 RefreshAsyncHelper *helper = NULL;
2744 ModestMailOperation *self = NULL;
2745 ModestMailOperationPrivate *priv = NULL;
2746 ModestMailOperationState *state;
2748 g_return_if_fail (user_data != NULL);
2749 g_return_if_fail (status != NULL);
2750 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2752 helper = (RefreshAsyncHelper *) user_data;
2753 self = helper->mail_op;
2754 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2756 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2758 priv->done = status->position;
2759 priv->total = status->of_total;
2761 state = modest_mail_operation_clone_state (self);
2763 /* This is not a GDK lock because we are a Tinymail callback and
2764 * Tinymail already acquires the Gdk lock */
2765 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2767 g_slice_free (ModestMailOperationState, state);
2771 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2773 RefreshAsyncUserCallback user_callback,
2776 ModestMailOperationPrivate *priv = NULL;
2777 RefreshAsyncHelper *helper = NULL;
2779 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2781 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2783 /* Get account and set it into mail_operation */
2784 priv->account = modest_tny_folder_get_account (folder);
2785 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2787 /* Create the helper */
2788 helper = g_slice_new0 (RefreshAsyncHelper);
2789 helper->mail_op = g_object_ref(self);
2790 helper->user_callback = user_callback;
2791 helper->user_data = user_data;
2793 /* Refresh the folder. TODO: tinymail could issue a status
2794 updates before the callback call then this could happen. We
2795 must review the design */
2796 modest_mail_operation_notify_start (self);
2797 tny_folder_refresh_async (folder,
2799 on_refresh_folder_status_update,
2805 modest_mail_operation_notify_start (ModestMailOperation *self)
2807 ModestMailOperationPrivate *priv = NULL;
2809 g_return_if_fail (self);
2811 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2813 /* Ensure that all the fields are filled correctly */
2814 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
2816 /* Notify the observers about the mail operation. We do not
2817 wrapp this emission because we assume that this function is
2818 always called from within the main lock */
2819 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
2824 * It's used by the mail operation queue to notify the observers
2825 * attached to that signal that the operation finished. We need to use
2826 * that because tinymail does not give us the progress of a given
2827 * operation when it finishes (it directly calls the operation
2831 modest_mail_operation_notify_end (ModestMailOperation *self)
2833 ModestMailOperationPrivate *priv = NULL;
2835 g_return_if_fail (self);
2837 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2839 /* Notify the observers about the mail operation end. We do
2840 not wrapp this emission because we assume that this
2841 function is always called from within the main lock */
2842 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
2844 /* Remove the error user data */
2845 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
2846 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
2850 modest_mail_operation_get_account (ModestMailOperation *self)
2852 ModestMailOperationPrivate *priv = NULL;
2854 g_return_val_if_fail (self, NULL);
2856 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2858 return (priv->account) ? g_object_ref (priv->account) : NULL;
2862 modest_mail_operation_noop (ModestMailOperation *self)
2864 ModestMailOperationPrivate *priv = NULL;
2866 g_return_if_fail (self);
2868 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2869 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2870 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2874 /* This mail operation does nothing actually */
2875 modest_mail_operation_notify_start (self);
2876 modest_mail_operation_notify_end (self);