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 const char *msgid1, *msgid2;
677 hdr1 = tny_msg_get_header(msg);
678 hdr2 = tny_msg_get_header(info->msg);
679 msgid1 = tny_header_get_message_id(hdr1);
680 msgid2 = tny_header_get_message_id(hdr2);
681 if (msgid1 == NULL) msgid1 = "(null)";
682 if (msgid2 == NULL) msgid2 = "(null)";
684 if (!strcmp (msgid1, msgid2)) {
685 ModestMailOperationPrivate *priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
686 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
688 common_send_mail_operation_end (queue, msg, info);
690 g_object_unref(G_OBJECT(hdr1));
691 g_object_unref(G_OBJECT(hdr2));
695 send_mail_error_happened_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
696 GError *error, gpointer userdata)
698 SendMsgInfo *info = (SendMsgInfo *) userdata;
699 TnyHeader *hdr1, *hdr2;
700 const char *msgid1, *msgid2;
702 hdr1 = tny_msg_get_header(msg);
703 hdr2 = tny_msg_get_header(info->msg);
704 msgid1 = tny_header_get_message_id(hdr1);
705 msgid2 = tny_header_get_message_id(hdr2);
706 if (msgid1 == NULL) msgid1 = "(null)";
707 if (msgid2 == NULL) msgid2 = "(null)";
709 if (!strcmp (msgid1, msgid2)) {
710 ModestMailOperationPrivate *priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
711 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
712 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
713 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
714 "modest: send mail failed\n");
716 common_send_mail_operation_end (queue, msg, info);
718 g_object_unref(G_OBJECT(hdr1));
719 g_object_unref(G_OBJECT(hdr2));
724 idle_create_msg_cb (gpointer idle_data)
726 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
728 /* This is a GDK lock because we are an idle callback and
729 * info->callback can contain Gtk+ code */
731 gdk_threads_enter (); /* CHECKED */
732 info->callback (info->mail_op, info->msg, info->userdata);
734 g_object_unref (info->mail_op);
736 g_object_unref (info->msg);
737 g_slice_free (CreateMsgIdleInfo, info);
738 gdk_threads_leave (); /* CHECKED */
744 create_msg_thread (gpointer thread_data)
746 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
747 TnyMsg *new_msg = NULL;
748 ModestMailOperationPrivate *priv;
750 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
751 if (info->html_body == NULL) {
752 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
753 info->bcc, info->subject, info->plain_body,
754 info->attachments_list);
756 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
757 info->bcc, info->subject, info->html_body,
758 info->plain_body, info->attachments_list,
765 /* Set priority flags in message */
766 header = tny_msg_get_header (new_msg);
767 tny_header_set_flag (header, info->priority_flags);
769 /* Set attachment flags in message */
770 if (info->attachments_list != NULL)
771 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
773 g_object_unref (G_OBJECT(header));
775 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
776 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
777 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
778 "modest: failed to create a new msg\n");
786 g_free (info->plain_body);
787 g_free (info->html_body);
788 g_free (info->subject);
789 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
790 g_list_free (info->attachments_list);
791 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
792 g_list_free (info->images_list);
794 if (info->callback) {
795 CreateMsgIdleInfo *idle_info;
796 idle_info = g_slice_new0 (CreateMsgIdleInfo);
797 idle_info->mail_op = g_object_ref (info->mail_op);
798 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
799 idle_info->callback = info->callback;
800 idle_info->userdata = info->userdata;
801 g_idle_add (idle_create_msg_cb, idle_info);
803 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
806 g_object_unref (info->mail_op);
807 g_slice_free (CreateMsgInfo, info);
812 modest_mail_operation_create_msg (ModestMailOperation *self,
813 const gchar *from, const gchar *to,
814 const gchar *cc, const gchar *bcc,
815 const gchar *subject, const gchar *plain_body,
816 const gchar *html_body,
817 const GList *attachments_list,
818 const GList *images_list,
819 TnyHeaderFlags priority_flags,
820 ModestMailOperationCreateMsgCallback callback,
823 CreateMsgInfo *info = NULL;
825 info = g_slice_new0 (CreateMsgInfo);
826 info->mail_op = g_object_ref (self);
828 info->from = g_strdup (from);
829 info->to = g_strdup (to);
830 info->cc = g_strdup (cc);
831 info->bcc = g_strdup (bcc);
832 info->subject = g_strdup (subject);
833 info->plain_body = g_strdup (plain_body);
834 info->html_body = g_strdup (html_body);
835 info->attachments_list = g_list_copy ((GList *) attachments_list);
836 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
837 info->images_list = g_list_copy ((GList *) images_list);
838 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
839 info->priority_flags = priority_flags;
841 info->callback = callback;
842 info->userdata = userdata;
844 g_thread_create (create_msg_thread, info, FALSE, NULL);
849 TnyTransportAccount *transport_account;
854 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
858 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
859 TnyFolder *draft_folder = NULL;
860 TnyFolder *outbox_folder = NULL;
868 /* Call mail operation */
869 modest_mail_operation_send_mail (self, info->transport_account, msg);
871 /* Remove old mail from its source folder */
872 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
873 TNY_FOLDER_TYPE_DRAFTS);
874 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
875 TNY_FOLDER_TYPE_OUTBOX);
876 if (info->draft_msg != NULL) {
877 TnyFolder *folder = NULL;
878 TnyFolder *src_folder = NULL;
879 TnyFolderType folder_type;
880 folder = tny_msg_get_folder (info->draft_msg);
881 if (folder == NULL) goto end;
882 folder_type = modest_tny_folder_guess_folder_type (folder);
884 if (folder_type == TNY_FOLDER_TYPE_INVALID)
885 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
887 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
888 src_folder = outbox_folder;
890 src_folder = draft_folder;
892 /* Note: This can fail (with a warning) if the message is not really already in a folder,
893 * because this function requires it to have a UID. */
894 header = tny_msg_get_header (info->draft_msg);
895 tny_folder_remove_msg (src_folder, header, NULL);
897 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
898 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
900 g_object_unref (header);
901 g_object_unref (folder);
908 g_object_unref (info->draft_msg);
910 g_object_unref (draft_folder);
912 g_object_unref (outbox_folder);
913 if (info->transport_account)
914 g_object_unref (info->transport_account);
915 g_slice_free (SendNewMailInfo, info);
919 modest_mail_operation_send_new_mail (ModestMailOperation *self,
920 TnyTransportAccount *transport_account,
922 const gchar *from, const gchar *to,
923 const gchar *cc, const gchar *bcc,
924 const gchar *subject, const gchar *plain_body,
925 const gchar *html_body,
926 const GList *attachments_list,
927 const GList *images_list,
928 TnyHeaderFlags priority_flags)
930 ModestMailOperationPrivate *priv = NULL;
931 SendNewMailInfo *info;
933 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
934 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
936 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
937 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
938 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
939 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
941 /* Check parametters */
943 /* Set status failed and set an error */
944 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
945 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
946 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
947 _("Error trying to send a mail. You need to set at least one recipient"));
950 info = g_slice_new0 (SendNewMailInfo);
951 info->transport_account = transport_account;
952 if (transport_account)
953 g_object_ref (transport_account);
954 info->draft_msg = draft_msg;
956 g_object_ref (draft_msg);
959 modest_mail_operation_notify_start (self);
960 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
961 attachments_list, images_list, priority_flags,
962 modest_mail_operation_send_new_mail_cb, info);
968 TnyTransportAccount *transport_account;
970 SaveToDraftstCallback callback;
974 ModestMailOperation *mailop;
975 } SaveToDraftsAddMsgInfo;
978 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
983 ModestMailOperationPrivate *priv = NULL;
984 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
986 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
989 g_warning ("%s: priv->error != NULL", __FUNCTION__);
990 g_error_free(priv->error);
993 priv->error = (err == NULL) ? NULL : g_error_copy(err);
995 if ((!priv->error) && (info->draft_msg != NULL)) {
996 TnyHeader *header = tny_msg_get_header (info->draft_msg);
997 TnyFolder *src_folder = tny_header_get_folder (header);
999 /* Remove the old draft */
1000 tny_folder_remove_msg (src_folder, header, NULL);
1002 /* Synchronize to expunge and to update the msg counts */
1003 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1004 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1006 g_object_unref (G_OBJECT(header));
1007 g_object_unref (G_OBJECT(src_folder));
1011 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1013 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1015 /* Call the user callback */
1017 info->callback (info->mailop, info->msg, info->user_data);
1019 if (info->transport_account)
1020 g_object_unref (G_OBJECT(info->transport_account));
1021 if (info->draft_msg)
1022 g_object_unref (G_OBJECT (info->draft_msg));
1024 g_object_unref (G_OBJECT(info->drafts));
1026 g_object_unref (G_OBJECT (info->msg));
1027 g_slice_free (SaveToDraftsAddMsgInfo, info);
1029 modest_mail_operation_notify_end (info->mailop);
1030 g_object_unref(info->mailop);
1035 TnyTransportAccount *transport_account;
1037 SaveToDraftstCallback callback;
1042 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1046 TnyFolder *drafts = NULL;
1047 ModestMailOperationPrivate *priv = NULL;
1048 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1050 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1053 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1054 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1055 "modest: failed to create a new msg\n");
1057 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1058 TNY_FOLDER_TYPE_DRAFTS);
1060 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1061 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1062 "modest: failed to create a new msg\n");
1067 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1068 cb_info->transport_account = g_object_ref(info->transport_account);
1069 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1070 cb_info->callback = info->callback;
1071 cb_info->user_data = info->user_data;
1072 cb_info->drafts = g_object_ref(drafts);
1073 cb_info->msg = g_object_ref(msg);
1074 cb_info->mailop = g_object_ref(self);
1075 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1078 /* Call the user callback */
1079 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1081 info->callback (self, msg, info->user_data);
1082 modest_mail_operation_notify_end (self);
1086 g_object_unref (G_OBJECT(drafts));
1087 if (info->draft_msg)
1088 g_object_unref (G_OBJECT (info->draft_msg));
1089 if (info->transport_account)
1090 g_object_unref (G_OBJECT(info->transport_account));
1091 g_slice_free (SaveToDraftsInfo, info);
1095 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1096 TnyTransportAccount *transport_account,
1098 const gchar *from, const gchar *to,
1099 const gchar *cc, const gchar *bcc,
1100 const gchar *subject, const gchar *plain_body,
1101 const gchar *html_body,
1102 const GList *attachments_list,
1103 const GList *images_list,
1104 TnyHeaderFlags priority_flags,
1105 SaveToDraftstCallback callback,
1108 ModestMailOperationPrivate *priv = NULL;
1109 SaveToDraftsInfo *info = NULL;
1111 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1112 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1114 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1116 /* Get account and set it into mail_operation */
1117 priv->account = g_object_ref (transport_account);
1118 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1120 info = g_slice_new0 (SaveToDraftsInfo);
1121 info->transport_account = g_object_ref (transport_account);
1122 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1123 info->callback = callback;
1124 info->user_data = user_data;
1126 modest_mail_operation_notify_start (self);
1127 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1128 attachments_list, images_list, priority_flags,
1129 modest_mail_operation_save_to_drafts_cb, info);
1134 ModestMailOperation *mail_op;
1135 TnyMimePart *mime_part;
1137 GetMimePartSizeCallback callback;
1139 } GetMimePartSizeInfo;
1141 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1142 /* We use this folder observer to track the headers that have been
1143 * added to a folder */
1146 TnyList *new_headers;
1147 } InternalFolderObserver;
1150 GObjectClass parent;
1151 } InternalFolderObserverClass;
1153 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1155 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1156 internal_folder_observer,
1158 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1162 foreach_add_item (gpointer header, gpointer user_data)
1164 tny_list_prepend (TNY_LIST (user_data),
1165 g_object_ref (G_OBJECT (header)));
1168 /* This is the method that looks for new messages in a folder */
1170 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1172 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1174 TnyFolderChangeChanged changed;
1176 changed = tny_folder_change_get_changed (change);
1178 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1181 /* Get added headers */
1182 list = tny_simple_list_new ();
1183 tny_folder_change_get_added_headers (change, list);
1185 /* Add them to the folder observer */
1186 tny_list_foreach (list, foreach_add_item,
1187 derived->new_headers);
1189 g_object_unref (G_OBJECT (list));
1194 internal_folder_observer_init (InternalFolderObserver *self)
1196 self->new_headers = tny_simple_list_new ();
1199 internal_folder_observer_finalize (GObject *object)
1201 InternalFolderObserver *self;
1203 self = (InternalFolderObserver *) object;
1204 g_object_unref (self->new_headers);
1206 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1209 tny_folder_observer_init (TnyFolderObserverIface *iface)
1211 iface->update_func = internal_folder_observer_update;
1214 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1216 GObjectClass *object_class;
1218 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1219 object_class = (GObjectClass*) klass;
1220 object_class->finalize = internal_folder_observer_finalize;
1225 ModestMailOperation *mail_op;
1226 gchar *account_name;
1227 UpdateAccountCallback callback;
1232 TnyFolderObserver *inbox_observer;
1233 guint update_timeout;
1234 RetrieveAllCallback retrieve_all_cb;
1235 } UpdateAccountInfo;
1239 destroy_update_account_info (UpdateAccountInfo *info)
1241 if (info->update_timeout) {
1242 g_source_remove (info->update_timeout);
1243 info->update_timeout = 0;
1246 g_free (info->account_name);
1247 g_object_unref (info->folders);
1248 g_object_unref (info->mail_op);
1249 g_slice_free (UpdateAccountInfo, info);
1253 update_account_get_msg_async_cb (TnyFolder *folder,
1259 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1261 /* Just delete the helper. Don't do anything with the new
1262 msg. There is also no need to check for errors */
1263 g_object_unref (msg_info->mail_op);
1264 g_object_unref (msg_info->header);
1265 g_slice_free (GetMsgInfo, msg_info);
1270 inbox_refreshed_cb (TnyFolder *inbox,
1275 UpdateAccountInfo *info;
1276 ModestMailOperationPrivate *priv;
1277 TnyIterator *new_headers_iter;
1278 GPtrArray *new_headers_array = NULL;
1279 gint max_size, retrieve_limit, i;
1280 ModestAccountMgr *mgr;
1281 ModestAccountRetrieveType retrieve_type;
1282 TnyList *new_headers = NULL;
1283 gboolean headers_only, ignore_limit;
1284 TnyTransportAccount *transport_account;
1285 ModestTnySendQueue *send_queue;
1287 info = (UpdateAccountInfo *) user_data;
1288 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1289 mgr = modest_runtime_get_account_mgr ();
1291 if (canceled || err || !inbox) {
1292 /* Try to send anyway */
1296 /* Get the message max size */
1297 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1298 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1300 max_size = G_MAXINT;
1302 max_size = max_size * KB;
1304 /* Create the new headers array. We need it to sort the
1305 new headers by date */
1306 new_headers_array = g_ptr_array_new ();
1307 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1308 while (!tny_iterator_is_done (new_headers_iter)) {
1309 TnyHeader *header = NULL;
1311 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1312 /* Apply per-message size limits */
1313 if (tny_header_get_message_size (header) < max_size)
1314 g_ptr_array_add (new_headers_array, g_object_ref (header));
1316 g_object_unref (header);
1317 tny_iterator_next (new_headers_iter);
1319 g_object_unref (new_headers_iter);
1320 tny_folder_remove_observer (inbox, info->inbox_observer);
1321 g_object_unref (info->inbox_observer);
1322 info->inbox_observer = NULL;
1324 /* Update the last updated key, even if we don't have to get new headers */
1325 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1327 if (new_headers_array->len == 0)
1330 /* Get per-account message amount retrieval limit */
1331 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1332 if (retrieve_limit == 0)
1333 retrieve_limit = G_MAXINT;
1335 /* Get per-account retrieval type */
1336 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1337 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1340 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1342 /* Ask the users if they want to retrieve all the messages
1343 even though the limit was exceeded */
1344 ignore_limit = FALSE;
1345 if (new_headers_array->len > retrieve_limit) {
1346 /* Ask the user if a callback has been specified and
1347 if the mail operation has a source (this means that
1348 was invoked by the user and not automatically by a
1350 if (info->retrieve_all_cb && priv->source)
1351 ignore_limit = info->retrieve_all_cb (priv->source,
1352 new_headers_array->len,
1356 if (!headers_only) {
1358 const gint msg_list_size = compute_message_array_size (new_headers_array);
1362 priv->total = new_headers_array->len;
1364 priv->total = MIN (new_headers_array->len, retrieve_limit);
1365 while (msg_num < priv->total) {
1366 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1367 TnyFolder *folder = tny_header_get_folder (header);
1368 GetMsgInfo *msg_info;
1370 /* Create the message info */
1371 msg_info = g_slice_new0 (GetMsgInfo);
1372 msg_info->mail_op = g_object_ref (info->mail_op);
1373 msg_info->header = g_object_ref (header);
1374 msg_info->total_bytes = msg_list_size;
1376 /* Get message in an async way */
1377 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1378 get_msg_status_cb, msg_info);
1380 g_object_unref (folder);
1386 /* Copy the headers to a list and free the array */
1387 new_headers = tny_simple_list_new ();
1388 for (i=0; i < new_headers_array->len; i++) {
1389 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1390 tny_list_append (new_headers, G_OBJECT (header));
1392 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1393 g_ptr_array_free (new_headers_array, FALSE);
1400 /* Get the transport account */
1401 transport_account = (TnyTransportAccount *)
1402 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1403 info->account_name);
1406 send_queue = modest_runtime_get_send_queue (transport_account);
1407 modest_tny_send_queue_try_to_send (send_queue);
1409 /* Check if the operation was a success */
1411 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1413 /* Set the account back to not busy */
1414 modest_account_mgr_set_account_busy (mgr, info->account_name, FALSE);
1416 /* Call the user callback */
1418 info->callback (info->mail_op, new_headers, info->user_data);
1420 /* Notify about operation end */
1421 modest_mail_operation_notify_end (info->mail_op);
1425 g_object_unref (new_headers);
1426 destroy_update_account_info (info);
1430 recurse_folders_async_cb (TnyFolderStore *folder_store,
1436 UpdateAccountInfo *info;
1437 ModestMailOperationPrivate *priv;
1439 info = (UpdateAccountInfo *) user_data;
1440 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1442 if (err || canceled) {
1443 /* Try to continue anyway */
1445 TnyIterator *iter = tny_list_create_iterator (list);
1446 while (!tny_iterator_is_done (iter)) {
1447 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1448 TnyList *folders = tny_simple_list_new ();
1450 /* Add to the list of all folders */
1451 tny_list_append (info->folders, (GObject *) folder);
1453 /* Add pending call */
1454 info->pending_calls++;
1456 tny_folder_store_get_folders_async (folder, folders, recurse_folders_async_cb,
1459 g_object_unref (G_OBJECT (folder));
1461 tny_iterator_next (iter);
1463 g_object_unref (G_OBJECT (iter));
1464 g_object_unref (G_OBJECT (list));
1467 /* Remove my own pending call */
1468 info->pending_calls--;
1470 /* This means that we have all the folders */
1471 if (info->pending_calls == 0) {
1472 TnyIterator *iter_all_folders;
1473 TnyFolder *inbox = NULL;
1475 iter_all_folders = tny_list_create_iterator (info->folders);
1477 /* Do a poke status over all folders */
1478 while (!tny_iterator_is_done (iter_all_folders) &&
1479 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1480 TnyFolder *folder = NULL;
1482 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1484 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1485 /* Get a reference to the INBOX */
1486 inbox = g_object_ref (folder);
1488 /* Issue a poke status over the folder */
1490 tny_folder_poke_status (folder);
1493 /* Free and go to next */
1494 g_object_unref (folder);
1495 tny_iterator_next (iter_all_folders);
1497 g_object_unref (iter_all_folders);
1499 /* Stop the progress notification */
1500 g_source_remove (info->update_timeout);
1501 info->update_timeout = 0;
1503 /* Refresh the INBOX */
1505 /* Refresh the folder. Our observer receives
1506 * the new emails during folder refreshes, so
1507 * we can use observer->new_headers
1509 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1510 tny_folder_add_observer (inbox, info->inbox_observer);
1512 /* Refresh the INBOX */
1513 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1514 g_object_unref (inbox);
1516 /* We could not perform the inbox refresh but
1517 we'll try to send mails anyway */
1518 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1524 * Issues the "progress-changed" signal. The timer won't be removed,
1525 * so you must call g_source_remove to stop the signal emission
1528 timeout_notify_progress (gpointer data)
1530 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1531 ModestMailOperationState *state;
1533 state = modest_mail_operation_clone_state (mail_op);
1535 /* This is a GDK lock because we are an idle callback and
1536 * the handlers of this signal can contain Gtk+ code */
1538 gdk_threads_enter (); /* CHECKED */
1539 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1540 gdk_threads_leave (); /* CHECKED */
1542 g_slice_free (ModestMailOperationState, state);
1548 modest_mail_operation_update_account (ModestMailOperation *self,
1549 const gchar *account_name,
1551 RetrieveAllCallback retrieve_all_cb,
1552 UpdateAccountCallback callback,
1555 UpdateAccountInfo *info = NULL;
1556 ModestMailOperationPrivate *priv = NULL;
1557 ModestTnyAccountStore *account_store = NULL;
1558 TnyStoreAccount *store_account = NULL;
1561 /* Init mail operation */
1562 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1565 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1566 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1568 /* Get the store account */
1569 account_store = modest_runtime_get_account_store ();
1570 store_account = (TnyStoreAccount *)
1571 modest_tny_account_store_get_server_account (account_store,
1573 TNY_ACCOUNT_TYPE_STORE);
1574 priv->account = g_object_ref (store_account);
1576 /* Create the helper object */
1577 info = g_slice_new0 (UpdateAccountInfo);
1578 info->pending_calls = 1;
1579 info->folders = tny_simple_list_new ();
1580 info->mail_op = g_object_ref (self);
1581 info->poke_all = poke_all;
1582 info->account_name = g_strdup (account_name);
1583 info->callback = callback;
1584 info->user_data = user_data;
1585 info->update_timeout = g_timeout_add (250, timeout_notify_progress, self);
1586 info->retrieve_all_cb = retrieve_all_cb;
1588 /* Set account busy */
1589 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1590 modest_mail_operation_notify_start (self);
1592 /* Get all folders and continue in the callback */
1593 folders = tny_simple_list_new ();
1594 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (store_account),
1595 folders, recurse_folders_async_cb,
1600 * Used to notify the queue from the main
1601 * loop. We call it inside an idle call to achieve that
1604 idle_notify_queue (gpointer data)
1606 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1608 gdk_threads_enter ();
1609 modest_mail_operation_notify_end (mail_op);
1610 gdk_threads_leave ();
1611 g_object_unref (mail_op);
1617 compare_headers_by_date (gconstpointer a,
1620 TnyHeader **header1, **header2;
1621 time_t sent1, sent2;
1623 header1 = (TnyHeader **) a;
1624 header2 = (TnyHeader **) b;
1626 sent1 = tny_header_get_date_sent (*header1);
1627 sent2 = tny_header_get_date_sent (*header2);
1629 /* We want the most recent ones (greater time_t) at the
1638 /* ******************************************************************* */
1639 /* ************************** STORE ACTIONS ************************* */
1640 /* ******************************************************************* */
1643 ModestMailOperation *mail_op;
1644 CreateFolderUserCallback callback;
1650 create_folder_cb (TnyFolderStore *parent_folder,
1652 TnyFolder *new_folder,
1656 ModestMailOperationPrivate *priv;
1657 CreateFolderInfo *info;
1659 info = (CreateFolderInfo *) user_data;
1660 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1662 if (canceled || err) {
1663 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1665 priv->error = g_error_copy (err);
1667 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1668 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1671 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1674 /* The user will unref the new_folder */
1676 info->callback (info->mail_op, parent_folder,
1677 new_folder, info->user_data);
1679 /* Notify about operation end */
1680 modest_mail_operation_notify_end (info->mail_op);
1683 g_object_unref (info->mail_op);
1684 g_slice_free (CreateFolderInfo, info);
1688 modest_mail_operation_create_folder (ModestMailOperation *self,
1689 TnyFolderStore *parent,
1691 CreateFolderUserCallback callback,
1694 ModestMailOperationPrivate *priv;
1696 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1697 g_return_if_fail (name);
1699 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1700 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1701 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1702 g_object_ref (parent) :
1703 modest_tny_folder_get_account (TNY_FOLDER (parent));
1705 /* Check for already existing folder */
1706 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1707 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1708 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1709 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1710 _CS("ckdg_ib_folder_already_exists"));
1714 if (TNY_IS_FOLDER (parent)) {
1715 /* Check folder rules */
1716 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1717 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1718 /* Set status failed and set an error */
1719 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1720 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1721 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1722 _("mail_in_ui_folder_create_error"));
1726 if (!strcmp (name, " ") || strchr (name, '/')) {
1727 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1728 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1729 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1730 _("mail_in_ui_folder_create_error"));
1734 CreateFolderInfo *info;
1736 info = g_slice_new0 (CreateFolderInfo);
1737 info->mail_op = g_object_ref (self);
1738 info->callback = callback;
1739 info->user_data = user_data;
1741 modest_mail_operation_notify_start (self);
1743 /* Create the folder */
1744 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1747 /* Call the user callback anyway */
1749 callback (self, parent, NULL, user_data);
1750 /* Notify about operation end */
1751 modest_mail_operation_notify_end (self);
1756 modest_mail_operation_remove_folder (ModestMailOperation *self,
1758 gboolean remove_to_trash)
1760 TnyAccount *account;
1761 ModestMailOperationPrivate *priv;
1762 ModestTnyFolderRules rules;
1764 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1765 g_return_if_fail (TNY_IS_FOLDER (folder));
1767 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1769 /* Check folder rules */
1770 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1771 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1772 /* Set status failed and set an error */
1773 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1774 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1775 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1776 _("mail_in_ui_folder_delete_error"));
1780 /* Get the account */
1781 account = modest_tny_folder_get_account (folder);
1782 priv->account = g_object_ref(account);
1783 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1785 /* Delete folder or move to trash */
1786 if (remove_to_trash) {
1787 TnyFolder *trash_folder = NULL;
1788 trash_folder = modest_tny_account_get_special_folder (account,
1789 TNY_FOLDER_TYPE_TRASH);
1790 /* TODO: error_handling */
1792 modest_mail_operation_notify_start (self);
1793 modest_mail_operation_xfer_folder (self, folder,
1794 TNY_FOLDER_STORE (trash_folder),
1796 g_object_unref (trash_folder);
1799 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1801 modest_mail_operation_notify_start (self);
1802 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1803 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1806 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1808 g_object_unref (parent);
1810 g_warning ("%s: could not get parent folder", __FUNCTION__);
1812 g_object_unref (G_OBJECT (account));
1815 /* Notify about operation end */
1816 modest_mail_operation_notify_end (self);
1820 transfer_folder_status_cb (GObject *obj,
1824 ModestMailOperation *self;
1825 ModestMailOperationPrivate *priv;
1826 ModestMailOperationState *state;
1827 XFerMsgAsyncHelper *helper;
1829 g_return_if_fail (status != NULL);
1830 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1832 helper = (XFerMsgAsyncHelper *) user_data;
1833 g_return_if_fail (helper != NULL);
1835 self = helper->mail_op;
1836 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1838 priv->done = status->position;
1839 priv->total = status->of_total;
1841 state = modest_mail_operation_clone_state (self);
1843 /* This is not a GDK lock because we are a Tinymail callback
1844 * which is already GDK locked by Tinymail */
1846 /* no gdk_threads_enter (), CHECKED */
1848 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1850 /* no gdk_threads_leave (), CHECKED */
1852 g_slice_free (ModestMailOperationState, state);
1857 transfer_folder_cb (TnyFolder *folder,
1859 TnyFolderStore *into,
1860 TnyFolder *new_folder,
1864 XFerMsgAsyncHelper *helper;
1865 ModestMailOperation *self = NULL;
1866 ModestMailOperationPrivate *priv = NULL;
1868 helper = (XFerMsgAsyncHelper *) user_data;
1869 g_return_if_fail (helper != NULL);
1871 self = helper->mail_op;
1872 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1875 priv->error = g_error_copy (err);
1877 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1878 } else if (cancelled) {
1879 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1880 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1881 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1882 _("Transference of %s was cancelled."),
1883 tny_folder_get_name (folder));
1886 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1889 /* Notify about operation end */
1890 modest_mail_operation_notify_end (self);
1892 /* If user defined callback function was defined, call it */
1893 if (helper->user_callback) {
1895 /* This is not a GDK lock because we are a Tinymail callback
1896 * which is already GDK locked by Tinymail */
1898 /* no gdk_threads_enter (), CHECKED */
1899 helper->user_callback (self, helper->user_data);
1900 /* no gdk_threads_leave () , CHECKED */
1904 g_object_unref (helper->mail_op);
1905 g_slice_free (XFerMsgAsyncHelper, helper);
1910 * This function checks if the new name is a valid name for our local
1911 * folders account. The new name could not be the same than then name
1912 * of any of the mandatory local folders
1914 * We can not rely on tinymail because tinymail does not check the
1915 * name of the virtual folders that the account could have in the case
1916 * that we're doing a rename (because it directly calls Camel which
1917 * knows nothing about our virtual folders).
1919 * In the case of an actual copy/move (i.e. move/copy a folder between
1920 * accounts) tinymail uses the tny_folder_store_create_account which
1921 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1922 * checks the new name of the folder, so this call in that case
1923 * wouldn't be needed. *But* NOTE that if tinymail changes its
1924 * implementation (if folder transfers within the same account is no
1925 * longer implemented as a rename) this call will allow Modest to work
1928 * If the new name is not valid, this function will set the status to
1929 * failed and will set also an error in the mail operation
1932 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1933 TnyFolderStore *into,
1934 const gchar *new_name)
1936 if (TNY_IS_ACCOUNT (into) &&
1937 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1938 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1940 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1941 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1942 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1943 _CS("ckdg_ib_folder_already_exists"));
1950 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1952 TnyFolderStore *parent,
1953 gboolean delete_original,
1954 XferAsyncUserCallback user_callback,
1957 ModestMailOperationPrivate *priv = NULL;
1958 ModestTnyFolderRules parent_rules = 0, rules;
1959 XFerMsgAsyncHelper *helper = NULL;
1960 const gchar *folder_name = NULL;
1961 const gchar *error_msg;
1963 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1964 g_return_if_fail (TNY_IS_FOLDER (folder));
1965 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1967 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1968 folder_name = tny_folder_get_name (folder);
1970 /* Set the error msg */
1971 error_msg = _("mail_in_ui_folder_move_target_error");
1973 /* Get account and set it into mail_operation */
1974 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1975 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1976 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1978 /* Get folder rules */
1979 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1980 if (TNY_IS_FOLDER (parent))
1981 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1983 /* Apply operation constraints */
1984 if ((gpointer) parent == (gpointer) folder ||
1985 (!TNY_IS_FOLDER_STORE (parent)) ||
1986 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1989 } else if (TNY_IS_FOLDER (parent) &&
1990 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1994 } else if (TNY_IS_FOLDER (parent) &&
1995 TNY_IS_FOLDER_STORE (folder) &&
1996 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1997 TNY_FOLDER_STORE (folder))) {
1998 /* Do not move a parent into a child */
2000 } else if (TNY_IS_FOLDER_STORE (parent) &&
2001 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2002 /* Check that the new folder name is not used by any
2005 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2006 /* Check that the new folder name is not used by any
2007 special local folder */
2010 /* Create the helper */
2011 helper = g_slice_new0 (XFerMsgAsyncHelper);
2012 helper->mail_op = g_object_ref (self);
2013 helper->dest_folder = NULL;
2014 helper->headers = NULL;
2015 helper->user_callback = user_callback;
2016 helper->user_data = user_data;
2018 /* Move/Copy folder */
2019 modest_mail_operation_notify_start (self);
2020 tny_folder_copy_async (folder,
2022 tny_folder_get_name (folder),
2025 transfer_folder_status_cb,
2031 /* Set status failed and set an error */
2032 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2033 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2034 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2037 /* Call the user callback if exists */
2039 user_callback (self, user_data);
2041 /* Notify the queue */
2042 modest_mail_operation_notify_end (self);
2046 modest_mail_operation_rename_folder (ModestMailOperation *self,
2050 ModestMailOperationPrivate *priv;
2051 ModestTnyFolderRules rules;
2052 XFerMsgAsyncHelper *helper;
2054 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2055 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2056 g_return_if_fail (name);
2058 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2060 /* Get account and set it into mail_operation */
2061 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2062 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2064 /* Check folder rules */
2065 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2066 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2067 /* Set status failed and set an error */
2068 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2069 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2070 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2071 _("FIXME: unable to rename"));
2073 /* Notify about operation end */
2074 modest_mail_operation_notify_end (self);
2075 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2076 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2077 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2078 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2079 _("FIXME: unable to rename"));
2080 /* Notify about operation end */
2081 modest_mail_operation_notify_end (self);
2083 TnyFolderStore *into;
2085 into = tny_folder_get_folder_store (folder);
2087 /* Check that the new folder name is not used by any
2088 special local folder */
2089 if (new_name_valid_if_local_account (priv, into, name)) {
2090 /* Create the helper */
2091 helper = g_slice_new0 (XFerMsgAsyncHelper);
2092 helper->mail_op = g_object_ref(self);
2093 helper->dest_folder = NULL;
2094 helper->headers = NULL;
2095 helper->user_callback = NULL;
2096 helper->user_data = NULL;
2098 /* Rename. Camel handles folder subscription/unsubscription */
2099 modest_mail_operation_notify_start (self);
2100 tny_folder_copy_async (folder, into, name, TRUE,
2102 transfer_folder_status_cb,
2105 modest_mail_operation_notify_end (self);
2107 g_object_unref (into);
2111 /* ******************************************************************* */
2112 /* ************************** MSG ACTIONS ************************* */
2113 /* ******************************************************************* */
2116 modest_mail_operation_get_msg (ModestMailOperation *self,
2118 GetMsgAsyncUserCallback user_callback,
2121 GetMsgInfo *helper = NULL;
2123 ModestMailOperationPrivate *priv;
2125 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2126 g_return_if_fail (TNY_IS_HEADER (header));
2128 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2129 folder = tny_header_get_folder (header);
2131 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2135 /* Get account and set it into mail_operation */
2136 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2138 /* Check for cached messages */
2139 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2140 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2142 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2144 /* Create the helper */
2145 helper = g_slice_new0 (GetMsgInfo);
2146 helper->header = g_object_ref (header);
2147 helper->mail_op = g_object_ref (self);
2148 helper->user_callback = user_callback;
2149 helper->user_data = user_data;
2150 helper->destroy_notify = NULL;
2151 helper->last_total_bytes = 0;
2152 helper->sum_total_bytes = 0;
2153 helper->total_bytes = tny_header_get_message_size (header);
2155 modest_mail_operation_notify_start (self);
2156 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2158 g_object_unref (G_OBJECT (folder));
2162 get_msg_status_cb (GObject *obj,
2166 GetMsgInfo *helper = NULL;
2168 g_return_if_fail (status != NULL);
2169 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2171 helper = (GetMsgInfo *) user_data;
2172 g_return_if_fail (helper != NULL);
2174 /* Notify progress */
2175 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2176 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2180 get_msg_async_cb (TnyFolder *folder,
2186 GetMsgInfo *info = NULL;
2187 ModestMailOperationPrivate *priv = NULL;
2190 info = (GetMsgInfo *) user_data;
2192 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2194 finished = (priv->done == priv->total) ? TRUE : FALSE;
2197 if (canceled || err) {
2198 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2200 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2201 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2204 /* Set the success status before calling the user callback */
2205 if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2206 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2210 /* Call the user callback */
2211 if (info->user_callback)
2212 info->user_callback (info->mail_op, info->header, canceled,
2213 msg, err, info->user_data);
2215 /* Notify about operation end if this is the last callback */
2217 /* Free user data */
2218 if (info->destroy_notify)
2219 info->destroy_notify (info->user_data);
2221 /* Notify about operation end */
2222 modest_mail_operation_notify_end (info->mail_op);
2226 g_object_unref (info->header);
2227 g_object_unref (info->mail_op);
2228 g_slice_free (GetMsgInfo, info);
2232 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2233 TnyList *header_list,
2234 GetMsgAsyncUserCallback user_callback,
2236 GDestroyNotify notify)
2238 ModestMailOperationPrivate *priv = NULL;
2239 gboolean size_ok = TRUE;
2241 TnyIterator *iter = NULL;
2243 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2245 /* Init mail operation */
2246 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2247 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2248 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2250 priv->total = tny_list_get_length(header_list);
2252 /* Get account and set it into mail_operation */
2253 if (tny_list_get_length (header_list) >= 1) {
2254 iter = tny_list_create_iterator (header_list);
2255 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2257 TnyFolder *folder = tny_header_get_folder (header);
2259 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2260 g_object_unref (folder);
2262 g_object_unref (header);
2265 if (tny_list_get_length (header_list) == 1) {
2266 g_object_unref (iter);
2271 /* Get msg size limit */
2272 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2273 MODEST_CONF_MSG_SIZE_LIMIT,
2276 g_clear_error (&(priv->error));
2277 max_size = G_MAXINT;
2279 max_size = max_size * KB;
2282 /* Check message size limits. If there is only one message
2283 always retrieve it */
2285 while (!tny_iterator_is_done (iter) && size_ok) {
2286 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2288 if (tny_header_get_message_size (header) >= max_size)
2290 g_object_unref (header);
2293 tny_iterator_next (iter);
2295 g_object_unref (iter);
2299 const gint msg_list_size = compute_message_list_size (header_list);
2301 modest_mail_operation_notify_start (self);
2302 iter = tny_list_create_iterator (header_list);
2303 while (!tny_iterator_is_done (iter)) {
2304 GetMsgInfo *msg_info = NULL;
2305 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2306 TnyFolder *folder = tny_header_get_folder (header);
2308 /* Create the message info */
2309 msg_info = g_slice_new0 (GetMsgInfo);
2310 msg_info->mail_op = g_object_ref (self);
2311 msg_info->header = g_object_ref (header);
2312 msg_info->user_callback = user_callback;
2313 msg_info->user_data = user_data;
2314 msg_info->destroy_notify = notify;
2315 msg_info->last_total_bytes = 0;
2316 msg_info->sum_total_bytes = 0;
2317 msg_info->total_bytes = msg_list_size;
2319 /* The callback will call it per each header */
2320 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2322 /* Free and go on */
2323 g_object_unref (header);
2324 g_object_unref (folder);
2325 tny_iterator_next (iter);
2327 g_object_unref (iter);
2329 /* Set status failed and set an error */
2330 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2331 /* FIXME: the error msg is different for pop */
2332 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2333 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2334 _("emev_ni_ui_imap_msg_size_exceed_error"));
2335 /* Remove from queue and free resources */
2336 modest_mail_operation_notify_end (self);
2344 modest_mail_operation_remove_msg (ModestMailOperation *self,
2346 gboolean remove_to_trash /*ignored*/)
2349 ModestMailOperationPrivate *priv;
2351 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2352 g_return_if_fail (TNY_IS_HEADER (header));
2354 if (remove_to_trash)
2355 g_warning ("remove to trash is not implemented");
2357 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2358 folder = tny_header_get_folder (header);
2360 /* Get account and set it into mail_operation */
2361 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2362 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2363 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2365 /* remove message from folder */
2366 tny_folder_remove_msg (folder, header, &(priv->error));
2368 gboolean expunge, leave_on_server;
2369 const gchar *account_name;
2370 TnyAccount *account;
2372 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2373 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2375 modest_mail_operation_notify_start (self);
2377 /* Get leave on server setting */
2378 account = tny_folder_get_account (folder);
2379 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2381 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2384 if (TNY_IS_CAMEL_POP_FOLDER (folder) && !leave_on_server)
2390 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2393 g_object_unref (account);
2399 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2401 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2404 g_object_unref (G_OBJECT (folder));
2406 /* Notify about operation end */
2407 modest_mail_operation_notify_end (self);
2411 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2413 gboolean remove_to_trash /*ignored*/)
2416 ModestMailOperationPrivate *priv;
2417 TnyIterator *iter = NULL;
2418 TnyHeader *header = NULL;
2419 TnyList *remove_headers = NULL;
2420 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2422 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2423 g_return_if_fail (TNY_IS_LIST (headers));
2425 if (remove_to_trash)
2426 g_warning ("remove to trash is not implemented");
2428 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2430 remove_headers = g_object_ref(headers);
2432 /* Get folder from first header and sync it */
2433 iter = tny_list_create_iterator (headers);
2434 header = TNY_HEADER (tny_iterator_get_current (iter));
2435 folder = tny_header_get_folder (header);
2437 /* Don't remove messages that are being sent */
2438 if (modest_tny_folder_is_local_folder (folder)) {
2439 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2441 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2442 TnyTransportAccount *traccount = NULL;
2443 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2444 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2446 ModestTnySendQueueStatus status;
2447 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2448 TnyIterator *iter = tny_list_create_iterator(headers);
2449 g_object_unref(remove_headers);
2450 remove_headers = TNY_LIST(tny_simple_list_new());
2451 while (!tny_iterator_is_done(iter)) {
2453 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2454 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2455 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2456 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2457 tny_list_append(remove_headers, G_OBJECT(hdr));
2459 g_object_unref(hdr);
2461 tny_iterator_next(iter);
2463 g_object_unref(iter);
2464 g_object_unref(traccount);
2468 /* Get account and set it into mail_operation */
2469 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2470 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2471 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2473 /* remove message from folder */
2474 modest_mail_operation_notify_start (self);
2476 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2478 gboolean expunge, leave_on_server;
2479 const gchar *account_name;
2480 TnyAccount *account;
2482 account = tny_folder_get_account (folder);
2483 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2485 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2488 if (TNY_IS_CAMEL_POP_FOLDER (folder) && !leave_on_server)
2494 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2496 g_object_unref (account);
2502 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2504 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2507 g_object_unref (remove_headers);
2508 g_object_unref (header);
2509 g_object_unref (iter);
2510 g_object_unref (G_OBJECT (folder));
2512 /* Notify about operation end */
2513 modest_mail_operation_notify_end (self);
2517 notify_progress_of_multiple_messages (ModestMailOperation *self,
2519 gint *last_total_bytes,
2520 gint *sum_total_bytes,
2522 gboolean increment_done)
2524 ModestMailOperationPrivate *priv;
2525 ModestMailOperationState *state;
2526 gboolean is_num_bytes;
2528 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2530 /* We know that tinymail sends us information about
2531 transferred bytes with this particular message */
2532 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2534 state = modest_mail_operation_clone_state (self);
2535 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2536 /* We know that we're in a different message when the
2537 total number of bytes to transfer is different. Of
2538 course it could fail if we're transferring messages
2539 of the same size, but this is a workarround */
2540 if (status->of_total != *last_total_bytes) {
2541 /* We need to increment the done when there is
2542 no information about each individual
2543 message, we need to do this in message
2544 transfers, and we don't do it for getting
2548 *sum_total_bytes += *last_total_bytes;
2549 *last_total_bytes = status->of_total;
2551 state->bytes_done += status->position + *sum_total_bytes;
2552 state->bytes_total = total_bytes;
2554 /* Notify the status change. Only notify about changes
2555 referred to bytes */
2556 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2560 g_slice_free (ModestMailOperationState, state);
2564 transfer_msgs_status_cb (GObject *obj,
2568 XFerMsgAsyncHelper *helper;
2570 g_return_if_fail (status != NULL);
2571 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2573 helper = (XFerMsgAsyncHelper *) user_data;
2574 g_return_if_fail (helper != NULL);
2576 /* Notify progress */
2577 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2578 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2583 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2585 XFerMsgAsyncHelper *helper;
2586 ModestMailOperation *self;
2587 ModestMailOperationPrivate *priv;
2588 TnyIterator *iter = NULL;
2589 TnyHeader *header = NULL;
2591 helper = (XFerMsgAsyncHelper *) user_data;
2592 self = helper->mail_op;
2594 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2597 priv->error = g_error_copy (err);
2599 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2600 } else if (cancelled) {
2601 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2602 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2603 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2604 _("Error trying to refresh the contents of %s"),
2605 tny_folder_get_name (folder));
2608 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2610 /* Update folder counts */
2611 tny_folder_poke_status (folder);
2612 tny_folder_poke_status (helper->dest_folder);
2616 /* Mark headers as deleted and seen */
2617 if ((helper->delete) &&
2618 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2619 iter = tny_list_create_iterator (helper->headers);
2620 while (!tny_iterator_is_done (iter)) {
2621 header = TNY_HEADER (tny_iterator_get_current (iter));
2622 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2623 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2624 g_object_unref (header);
2626 tny_iterator_next (iter);
2632 /* Notify about operation end */
2633 modest_mail_operation_notify_end (self);
2635 /* If user defined callback function was defined, call it */
2636 if (helper->user_callback) {
2637 /* This is not a GDK lock because we are a Tinymail callback and
2638 * Tinymail already acquires the Gdk lock */
2640 /* no gdk_threads_enter (), CHECKED */
2641 helper->user_callback (self, helper->user_data);
2642 /* no gdk_threads_leave (), CHECKED */
2646 if (helper->headers)
2647 g_object_unref (helper->headers);
2648 if (helper->dest_folder)
2649 g_object_unref (helper->dest_folder);
2650 if (helper->mail_op)
2651 g_object_unref (helper->mail_op);
2653 g_object_unref (folder);
2655 g_object_unref (iter);
2656 g_slice_free (XFerMsgAsyncHelper, helper);
2660 compute_message_list_size (TnyList *headers)
2665 iter = tny_list_create_iterator (headers);
2666 while (!tny_iterator_is_done (iter)) {
2667 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2668 size += tny_header_get_message_size (header);
2669 g_object_unref (header);
2670 tny_iterator_next (iter);
2672 g_object_unref (iter);
2678 compute_message_array_size (GPtrArray *headers)
2683 for (i = 0; i < headers->len; i++) {
2684 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2685 size += tny_header_get_message_size (header);
2693 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2696 gboolean delete_original,
2697 XferAsyncUserCallback user_callback,
2700 ModestMailOperationPrivate *priv = NULL;
2701 TnyIterator *iter = NULL;
2702 TnyFolder *src_folder = NULL;
2703 XFerMsgAsyncHelper *helper = NULL;
2704 TnyHeader *header = NULL;
2705 ModestTnyFolderRules rules = 0;
2707 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2708 g_return_if_fail (headers && TNY_IS_LIST (headers));
2709 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2711 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2712 priv->total = tny_list_get_length (headers);
2714 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2715 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2717 /* Apply folder rules */
2718 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2719 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2720 /* Set status failed and set an error */
2721 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2722 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2723 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2724 _CS("ckct_ib_unable_to_paste_here"));
2725 /* Notify the queue */
2726 modest_mail_operation_notify_end (self);
2730 /* Get source folder */
2731 iter = tny_list_create_iterator (headers);
2732 header = TNY_HEADER (tny_iterator_get_current (iter));
2734 src_folder = tny_header_get_folder (header);
2735 g_object_unref (header);
2737 g_object_unref (iter);
2739 if (src_folder == NULL) {
2740 /* Notify the queue */
2741 modest_mail_operation_notify_end (self);
2743 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2748 /* Check folder source and destination */
2749 if (src_folder == folder) {
2750 /* Set status failed and set an error */
2751 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2752 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2753 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2754 _("mail_in_ui_folder_copy_target_error"));
2756 /* Notify the queue */
2757 modest_mail_operation_notify_end (self);
2760 g_object_unref (src_folder);
2764 /* Create the helper */
2765 helper = g_slice_new0 (XFerMsgAsyncHelper);
2766 helper->mail_op = g_object_ref(self);
2767 helper->dest_folder = g_object_ref(folder);
2768 helper->headers = g_object_ref(headers);
2769 helper->user_callback = user_callback;
2770 helper->user_data = user_data;
2771 helper->delete = delete_original;
2772 helper->last_total_bytes = 0;
2773 helper->sum_total_bytes = 0;
2774 helper->total_bytes = compute_message_list_size (headers);
2776 /* Get account and set it into mail_operation */
2777 priv->account = modest_tny_folder_get_account (src_folder);
2779 /* Transfer messages */
2780 modest_mail_operation_notify_start (self);
2781 tny_folder_transfer_msgs_async (src_folder,
2786 transfer_msgs_status_cb,
2792 on_refresh_folder (TnyFolder *folder,
2797 RefreshAsyncHelper *helper = NULL;
2798 ModestMailOperation *self = NULL;
2799 ModestMailOperationPrivate *priv = NULL;
2801 helper = (RefreshAsyncHelper *) user_data;
2802 self = helper->mail_op;
2803 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2805 g_return_if_fail(priv!=NULL);
2808 priv->error = g_error_copy (error);
2809 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2814 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2815 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2816 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2817 _("Error trying to refresh the contents of %s"),
2818 tny_folder_get_name (folder));
2822 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2825 /* Call user defined callback, if it exists */
2826 if (helper->user_callback) {
2828 /* This is not a GDK lock because we are a Tinymail callback and
2829 * Tinymail already acquires the Gdk lock */
2830 helper->user_callback (self, folder, helper->user_data);
2834 g_slice_free (RefreshAsyncHelper, helper);
2836 /* Notify about operation end */
2837 modest_mail_operation_notify_end (self);
2838 g_object_unref(self);
2842 on_refresh_folder_status_update (GObject *obj,
2846 RefreshAsyncHelper *helper = NULL;
2847 ModestMailOperation *self = NULL;
2848 ModestMailOperationPrivate *priv = NULL;
2849 ModestMailOperationState *state;
2851 g_return_if_fail (user_data != NULL);
2852 g_return_if_fail (status != NULL);
2853 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2855 helper = (RefreshAsyncHelper *) user_data;
2856 self = helper->mail_op;
2857 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2859 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2861 priv->done = status->position;
2862 priv->total = status->of_total;
2864 state = modest_mail_operation_clone_state (self);
2866 /* This is not a GDK lock because we are a Tinymail callback and
2867 * Tinymail already acquires the Gdk lock */
2868 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2870 g_slice_free (ModestMailOperationState, state);
2874 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2876 RefreshAsyncUserCallback user_callback,
2879 ModestMailOperationPrivate *priv = NULL;
2880 RefreshAsyncHelper *helper = NULL;
2882 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2884 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2886 /* Get account and set it into mail_operation */
2887 priv->account = modest_tny_folder_get_account (folder);
2888 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2890 /* Create the helper */
2891 helper = g_slice_new0 (RefreshAsyncHelper);
2892 helper->mail_op = g_object_ref(self);
2893 helper->user_callback = user_callback;
2894 helper->user_data = user_data;
2896 /* Refresh the folder. TODO: tinymail could issue a status
2897 updates before the callback call then this could happen. We
2898 must review the design */
2899 modest_mail_operation_notify_start (self);
2900 tny_folder_refresh_async (folder,
2902 on_refresh_folder_status_update,
2908 modest_mail_operation_notify_start (ModestMailOperation *self)
2910 ModestMailOperationPrivate *priv = NULL;
2912 g_return_if_fail (self);
2914 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2916 /* Ensure that all the fields are filled correctly */
2917 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
2919 /* Notify the observers about the mail operation. We do not
2920 wrapp this emission because we assume that this function is
2921 always called from within the main lock */
2922 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
2927 * It's used by the mail operation queue to notify the observers
2928 * attached to that signal that the operation finished. We need to use
2929 * that because tinymail does not give us the progress of a given
2930 * operation when it finishes (it directly calls the operation
2934 modest_mail_operation_notify_end (ModestMailOperation *self)
2936 ModestMailOperationPrivate *priv = NULL;
2938 g_return_if_fail (self);
2940 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2942 /* Notify the observers about the mail operation end. We do
2943 not wrapp this emission because we assume that this
2944 function is always called from within the main lock */
2945 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
2947 /* Remove the error user data */
2948 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
2949 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
2953 modest_mail_operation_get_account (ModestMailOperation *self)
2955 ModestMailOperationPrivate *priv = NULL;
2957 g_return_val_if_fail (self, NULL);
2959 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2961 return (priv->account) ? g_object_ref (priv->account) : NULL;
2965 modest_mail_operation_noop (ModestMailOperation *self)
2967 ModestMailOperationPrivate *priv = NULL;
2969 g_return_if_fail (self);
2971 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2972 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2973 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2977 /* This mail operation does nothing actually */
2978 modest_mail_operation_notify_start (self);
2979 modest_mail_operation_notify_end (self);