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);
808 if (new_msg) g_object_unref(new_msg);
813 modest_mail_operation_create_msg (ModestMailOperation *self,
814 const gchar *from, const gchar *to,
815 const gchar *cc, const gchar *bcc,
816 const gchar *subject, const gchar *plain_body,
817 const gchar *html_body,
818 const GList *attachments_list,
819 const GList *images_list,
820 TnyHeaderFlags priority_flags,
821 ModestMailOperationCreateMsgCallback callback,
824 CreateMsgInfo *info = NULL;
826 info = g_slice_new0 (CreateMsgInfo);
827 info->mail_op = g_object_ref (self);
829 info->from = g_strdup (from);
830 info->to = g_strdup (to);
831 info->cc = g_strdup (cc);
832 info->bcc = g_strdup (bcc);
833 info->subject = g_strdup (subject);
834 info->plain_body = g_strdup (plain_body);
835 info->html_body = g_strdup (html_body);
836 info->attachments_list = g_list_copy ((GList *) attachments_list);
837 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
838 info->images_list = g_list_copy ((GList *) images_list);
839 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
840 info->priority_flags = priority_flags;
842 info->callback = callback;
843 info->userdata = userdata;
845 g_thread_create (create_msg_thread, info, FALSE, NULL);
850 TnyTransportAccount *transport_account;
855 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
859 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
860 TnyFolder *draft_folder = NULL;
861 TnyFolder *outbox_folder = NULL;
869 /* Call mail operation */
870 modest_mail_operation_send_mail (self, info->transport_account, msg);
872 /* Remove old mail from its source folder */
873 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
874 TNY_FOLDER_TYPE_DRAFTS);
875 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
876 TNY_FOLDER_TYPE_OUTBOX);
877 if (info->draft_msg != NULL) {
878 TnyFolder *folder = NULL;
879 TnyFolder *src_folder = NULL;
880 TnyFolderType folder_type;
881 folder = tny_msg_get_folder (info->draft_msg);
882 if (folder == NULL) goto end;
883 folder_type = modest_tny_folder_guess_folder_type (folder);
885 if (folder_type == TNY_FOLDER_TYPE_INVALID)
886 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
888 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
889 src_folder = outbox_folder;
891 src_folder = draft_folder;
893 /* Note: This can fail (with a warning) if the message is not really already in a folder,
894 * because this function requires it to have a UID. */
895 header = tny_msg_get_header (info->draft_msg);
896 tny_folder_remove_msg (src_folder, header, NULL);
898 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
899 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
901 g_object_unref (header);
902 g_object_unref (folder);
909 g_object_unref (info->draft_msg);
911 g_object_unref (draft_folder);
913 g_object_unref (outbox_folder);
914 if (info->transport_account)
915 g_object_unref (info->transport_account);
916 g_slice_free (SendNewMailInfo, info);
920 modest_mail_operation_send_new_mail (ModestMailOperation *self,
921 TnyTransportAccount *transport_account,
923 const gchar *from, const gchar *to,
924 const gchar *cc, const gchar *bcc,
925 const gchar *subject, const gchar *plain_body,
926 const gchar *html_body,
927 const GList *attachments_list,
928 const GList *images_list,
929 TnyHeaderFlags priority_flags)
931 ModestMailOperationPrivate *priv = NULL;
932 SendNewMailInfo *info;
934 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
935 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
937 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
938 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
939 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
940 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
942 /* Check parametters */
944 /* Set status failed and set an error */
945 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
946 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
947 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
948 _("Error trying to send a mail. You need to set at least one recipient"));
951 info = g_slice_new0 (SendNewMailInfo);
952 info->transport_account = transport_account;
953 if (transport_account)
954 g_object_ref (transport_account);
955 info->draft_msg = draft_msg;
957 g_object_ref (draft_msg);
960 modest_mail_operation_notify_start (self);
961 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
962 attachments_list, images_list, priority_flags,
963 modest_mail_operation_send_new_mail_cb, info);
969 TnyTransportAccount *transport_account;
971 SaveToDraftstCallback callback;
975 ModestMailOperation *mailop;
976 } SaveToDraftsAddMsgInfo;
979 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
984 ModestMailOperationPrivate *priv = NULL;
985 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
987 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
990 g_warning ("%s: priv->error != NULL", __FUNCTION__);
991 g_error_free(priv->error);
994 priv->error = (err == NULL) ? NULL : g_error_copy(err);
996 if ((!priv->error) && (info->draft_msg != NULL)) {
997 TnyHeader *header = tny_msg_get_header (info->draft_msg);
998 TnyFolder *src_folder = tny_header_get_folder (header);
1000 /* Remove the old draft */
1001 tny_folder_remove_msg (src_folder, header, NULL);
1003 /* Synchronize to expunge and to update the msg counts */
1004 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1005 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1007 g_object_unref (G_OBJECT(header));
1008 g_object_unref (G_OBJECT(src_folder));
1012 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1014 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1016 /* Call the user callback */
1018 info->callback (info->mailop, info->msg, info->user_data);
1020 if (info->transport_account)
1021 g_object_unref (G_OBJECT(info->transport_account));
1022 if (info->draft_msg)
1023 g_object_unref (G_OBJECT (info->draft_msg));
1025 g_object_unref (G_OBJECT(info->drafts));
1027 g_object_unref (G_OBJECT (info->msg));
1028 g_slice_free (SaveToDraftsAddMsgInfo, info);
1030 modest_mail_operation_notify_end (info->mailop);
1031 g_object_unref(info->mailop);
1036 TnyTransportAccount *transport_account;
1038 SaveToDraftstCallback callback;
1043 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1047 TnyFolder *drafts = NULL;
1048 ModestMailOperationPrivate *priv = NULL;
1049 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1051 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1054 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1055 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1056 "modest: failed to create a new msg\n");
1058 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1059 TNY_FOLDER_TYPE_DRAFTS);
1061 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1062 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1063 "modest: failed to create a new msg\n");
1068 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1069 cb_info->transport_account = g_object_ref(info->transport_account);
1070 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1071 cb_info->callback = info->callback;
1072 cb_info->user_data = info->user_data;
1073 cb_info->drafts = g_object_ref(drafts);
1074 cb_info->msg = g_object_ref(msg);
1075 cb_info->mailop = g_object_ref(self);
1076 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1079 /* Call the user callback */
1080 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1082 info->callback (self, msg, info->user_data);
1083 modest_mail_operation_notify_end (self);
1087 g_object_unref (G_OBJECT(drafts));
1088 if (info->draft_msg)
1089 g_object_unref (G_OBJECT (info->draft_msg));
1090 if (info->transport_account)
1091 g_object_unref (G_OBJECT(info->transport_account));
1092 g_slice_free (SaveToDraftsInfo, info);
1096 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1097 TnyTransportAccount *transport_account,
1099 const gchar *from, const gchar *to,
1100 const gchar *cc, const gchar *bcc,
1101 const gchar *subject, const gchar *plain_body,
1102 const gchar *html_body,
1103 const GList *attachments_list,
1104 const GList *images_list,
1105 TnyHeaderFlags priority_flags,
1106 SaveToDraftstCallback callback,
1109 ModestMailOperationPrivate *priv = NULL;
1110 SaveToDraftsInfo *info = NULL;
1112 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1113 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1115 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1117 /* Get account and set it into mail_operation */
1118 priv->account = g_object_ref (transport_account);
1119 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1121 info = g_slice_new0 (SaveToDraftsInfo);
1122 info->transport_account = g_object_ref (transport_account);
1123 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1124 info->callback = callback;
1125 info->user_data = user_data;
1127 modest_mail_operation_notify_start (self);
1128 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1129 attachments_list, images_list, priority_flags,
1130 modest_mail_operation_save_to_drafts_cb, info);
1135 ModestMailOperation *mail_op;
1136 TnyMimePart *mime_part;
1138 GetMimePartSizeCallback callback;
1140 } GetMimePartSizeInfo;
1142 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1143 /* We use this folder observer to track the headers that have been
1144 * added to a folder */
1147 TnyList *new_headers;
1148 } InternalFolderObserver;
1151 GObjectClass parent;
1152 } InternalFolderObserverClass;
1154 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1156 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1157 internal_folder_observer,
1159 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1163 foreach_add_item (gpointer header, gpointer user_data)
1165 tny_list_prepend (TNY_LIST (user_data),
1166 g_object_ref (G_OBJECT (header)));
1169 /* This is the method that looks for new messages in a folder */
1171 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1173 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1175 TnyFolderChangeChanged changed;
1177 changed = tny_folder_change_get_changed (change);
1179 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1182 /* Get added headers */
1183 list = tny_simple_list_new ();
1184 tny_folder_change_get_added_headers (change, list);
1186 /* Add them to the folder observer */
1187 tny_list_foreach (list, foreach_add_item,
1188 derived->new_headers);
1190 g_object_unref (G_OBJECT (list));
1195 internal_folder_observer_init (InternalFolderObserver *self)
1197 self->new_headers = tny_simple_list_new ();
1200 internal_folder_observer_finalize (GObject *object)
1202 InternalFolderObserver *self;
1204 self = (InternalFolderObserver *) object;
1205 g_object_unref (self->new_headers);
1207 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1210 tny_folder_observer_init (TnyFolderObserverIface *iface)
1212 iface->update_func = internal_folder_observer_update;
1215 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1217 GObjectClass *object_class;
1219 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1220 object_class = (GObjectClass*) klass;
1221 object_class->finalize = internal_folder_observer_finalize;
1226 ModestMailOperation *mail_op;
1227 gchar *account_name;
1228 UpdateAccountCallback callback;
1233 TnyFolderObserver *inbox_observer;
1234 RetrieveAllCallback retrieve_all_cb;
1235 } UpdateAccountInfo;
1239 destroy_update_account_info (UpdateAccountInfo *info)
1241 g_free (info->account_name);
1242 g_object_unref (info->folders);
1243 g_object_unref (info->mail_op);
1244 g_slice_free (UpdateAccountInfo, info);
1248 update_account_get_msg_async_cb (TnyFolder *folder,
1254 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1256 /* Just delete the helper. Don't do anything with the new
1257 msg. There is also no need to check for errors */
1258 g_object_unref (msg_info->mail_op);
1259 g_object_unref (msg_info->header);
1260 g_slice_free (GetMsgInfo, msg_info);
1265 inbox_refreshed_cb (TnyFolder *inbox,
1270 UpdateAccountInfo *info;
1271 ModestMailOperationPrivate *priv;
1272 TnyIterator *new_headers_iter;
1273 GPtrArray *new_headers_array = NULL;
1274 gint max_size, retrieve_limit, i;
1275 ModestAccountMgr *mgr;
1276 ModestAccountRetrieveType retrieve_type;
1277 TnyList *new_headers = NULL;
1278 gboolean headers_only, ignore_limit;
1279 TnyTransportAccount *transport_account;
1280 ModestTnySendQueue *send_queue;
1282 info = (UpdateAccountInfo *) user_data;
1283 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1284 mgr = modest_runtime_get_account_mgr ();
1286 if (canceled || err || !inbox) {
1287 /* Try to send anyway */
1291 /* Get the message max size */
1292 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1293 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1295 max_size = G_MAXINT;
1297 max_size = max_size * KB;
1299 /* Create the new headers array. We need it to sort the
1300 new headers by date */
1301 new_headers_array = g_ptr_array_new ();
1302 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1303 while (!tny_iterator_is_done (new_headers_iter)) {
1304 TnyHeader *header = NULL;
1306 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1307 /* Apply per-message size limits */
1308 if (tny_header_get_message_size (header) < max_size)
1309 g_ptr_array_add (new_headers_array, g_object_ref (header));
1311 g_object_unref (header);
1312 tny_iterator_next (new_headers_iter);
1314 g_object_unref (new_headers_iter);
1315 tny_folder_remove_observer (inbox, info->inbox_observer);
1316 g_object_unref (info->inbox_observer);
1317 info->inbox_observer = NULL;
1319 /* Update the last updated key, even if we don't have to get new headers */
1320 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1322 if (new_headers_array->len == 0)
1325 /* Get per-account message amount retrieval limit */
1326 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1327 if (retrieve_limit == 0)
1328 retrieve_limit = G_MAXINT;
1330 /* Get per-account retrieval type */
1331 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1332 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1335 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1337 /* Ask the users if they want to retrieve all the messages
1338 even though the limit was exceeded */
1339 ignore_limit = FALSE;
1340 if (new_headers_array->len > retrieve_limit) {
1341 /* Ask the user if a callback has been specified and
1342 if the mail operation has a source (this means that
1343 was invoked by the user and not automatically by a
1345 if (info->retrieve_all_cb && priv->source)
1346 ignore_limit = info->retrieve_all_cb (priv->source,
1347 new_headers_array->len,
1351 if (!headers_only) {
1353 const gint msg_list_size = compute_message_array_size (new_headers_array);
1357 priv->total = new_headers_array->len;
1359 priv->total = MIN (new_headers_array->len, retrieve_limit);
1360 while (msg_num < priv->total) {
1361 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1362 TnyFolder *folder = tny_header_get_folder (header);
1363 GetMsgInfo *msg_info;
1365 /* Create the message info */
1366 msg_info = g_slice_new0 (GetMsgInfo);
1367 msg_info->mail_op = g_object_ref (info->mail_op);
1368 msg_info->header = g_object_ref (header);
1369 msg_info->total_bytes = msg_list_size;
1371 /* Get message in an async way */
1372 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1373 get_msg_status_cb, msg_info);
1375 g_object_unref (folder);
1381 /* Copy the headers to a list and free the array */
1382 new_headers = tny_simple_list_new ();
1383 for (i=0; i < new_headers_array->len; i++) {
1384 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1385 tny_list_append (new_headers, G_OBJECT (header));
1387 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1388 g_ptr_array_free (new_headers_array, FALSE);
1395 /* Get the transport account */
1396 transport_account = (TnyTransportAccount *)
1397 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1398 info->account_name);
1401 send_queue = modest_runtime_get_send_queue (transport_account);
1402 modest_tny_send_queue_try_to_send (send_queue);
1404 /* Check if the operation was a success */
1406 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1408 /* Set the account back to not busy */
1409 modest_account_mgr_set_account_busy (mgr, info->account_name, FALSE);
1411 /* Call the user callback */
1413 info->callback (info->mail_op, new_headers, info->user_data);
1415 /* Notify about operation end */
1416 modest_mail_operation_notify_end (info->mail_op);
1420 g_object_unref (new_headers);
1421 destroy_update_account_info (info);
1425 recurse_folders_async_cb (TnyFolderStore *folder_store,
1431 UpdateAccountInfo *info;
1432 ModestMailOperationPrivate *priv;
1434 info = (UpdateAccountInfo *) user_data;
1435 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1437 if (err || canceled) {
1438 /* Try to continue anyway */
1440 TnyIterator *iter = tny_list_create_iterator (list);
1441 while (!tny_iterator_is_done (iter)) {
1442 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1443 TnyList *folders = tny_simple_list_new ();
1445 /* Add to the list of all folders */
1446 tny_list_append (info->folders, (GObject *) folder);
1448 /* Add pending call */
1449 info->pending_calls++;
1451 tny_folder_store_get_folders_async (folder, folders, NULL, recurse_folders_async_cb,
1454 g_object_unref (G_OBJECT (folder));
1456 tny_iterator_next (iter);
1458 g_object_unref (G_OBJECT (iter));
1459 g_object_unref (G_OBJECT (list));
1462 /* Remove my own pending call */
1463 info->pending_calls--;
1465 /* This means that we have all the folders */
1466 if (info->pending_calls == 0) {
1467 TnyIterator *iter_all_folders;
1468 TnyFolder *inbox = NULL;
1470 iter_all_folders = tny_list_create_iterator (info->folders);
1472 /* Do a poke status over all folders */
1473 while (!tny_iterator_is_done (iter_all_folders) &&
1474 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1475 TnyFolder *folder = NULL;
1477 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1479 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1480 /* Get a reference to the INBOX */
1481 inbox = g_object_ref (folder);
1483 /* Issue a poke status over the folder */
1485 tny_folder_poke_status (folder);
1488 /* Free and go to next */
1489 g_object_unref (folder);
1490 tny_iterator_next (iter_all_folders);
1492 g_object_unref (iter_all_folders);
1494 /* Refresh the INBOX */
1496 /* Refresh the folder. Our observer receives
1497 * the new emails during folder refreshes, so
1498 * we can use observer->new_headers
1500 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1501 tny_folder_add_observer (inbox, info->inbox_observer);
1503 /* Refresh the INBOX */
1504 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1505 g_object_unref (inbox);
1507 /* We could not perform the inbox refresh but
1508 we'll try to send mails anyway */
1509 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1515 modest_mail_operation_update_account (ModestMailOperation *self,
1516 const gchar *account_name,
1518 RetrieveAllCallback retrieve_all_cb,
1519 UpdateAccountCallback callback,
1522 UpdateAccountInfo *info = NULL;
1523 ModestMailOperationPrivate *priv = NULL;
1524 ModestTnyAccountStore *account_store = NULL;
1525 TnyStoreAccount *store_account = NULL;
1528 /* Init mail operation */
1529 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1532 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1533 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1535 /* Get the store account */
1536 account_store = modest_runtime_get_account_store ();
1537 store_account = (TnyStoreAccount *)
1538 modest_tny_account_store_get_server_account (account_store,
1540 TNY_ACCOUNT_TYPE_STORE);
1541 priv->account = g_object_ref (store_account);
1543 /* Create the helper object */
1544 info = g_slice_new0 (UpdateAccountInfo);
1545 info->pending_calls = 1;
1546 info->folders = tny_simple_list_new ();
1547 info->mail_op = g_object_ref (self);
1548 info->poke_all = poke_all;
1549 info->account_name = g_strdup (account_name);
1550 info->callback = callback;
1551 info->user_data = user_data;
1552 info->retrieve_all_cb = retrieve_all_cb;
1554 /* Set account busy */
1555 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1556 modest_mail_operation_notify_start (self);
1558 /* notify about the start of the operation */
1559 ModestMailOperationState *state;
1560 state = modest_mail_operation_clone_state (self);
1564 /* Start notifying progress */
1565 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
1567 g_slice_free (ModestMailOperationState, state);
1569 /* Get all folders and continue in the callback */
1570 folders = tny_simple_list_new ();
1571 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (store_account),
1572 folders, recurse_folders_async_cb,
1577 * Used to notify the queue from the main
1578 * loop. We call it inside an idle call to achieve that
1581 idle_notify_queue (gpointer data)
1583 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1585 gdk_threads_enter ();
1586 modest_mail_operation_notify_end (mail_op);
1587 gdk_threads_leave ();
1588 g_object_unref (mail_op);
1594 compare_headers_by_date (gconstpointer a,
1597 TnyHeader **header1, **header2;
1598 time_t sent1, sent2;
1600 header1 = (TnyHeader **) a;
1601 header2 = (TnyHeader **) b;
1603 sent1 = tny_header_get_date_sent (*header1);
1604 sent2 = tny_header_get_date_sent (*header2);
1606 /* We want the most recent ones (greater time_t) at the
1615 /* ******************************************************************* */
1616 /* ************************** STORE ACTIONS ************************* */
1617 /* ******************************************************************* */
1620 ModestMailOperation *mail_op;
1621 CreateFolderUserCallback callback;
1627 create_folder_cb (TnyFolderStore *parent_folder,
1629 TnyFolder *new_folder,
1633 ModestMailOperationPrivate *priv;
1634 CreateFolderInfo *info;
1636 info = (CreateFolderInfo *) user_data;
1637 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1639 if (canceled || err) {
1640 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1642 priv->error = g_error_copy (err);
1644 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1645 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1648 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1651 /* The user will unref the new_folder */
1653 info->callback (info->mail_op, parent_folder,
1654 new_folder, info->user_data);
1656 /* Notify about operation end */
1657 modest_mail_operation_notify_end (info->mail_op);
1660 g_object_unref (info->mail_op);
1661 g_slice_free (CreateFolderInfo, info);
1665 modest_mail_operation_create_folder (ModestMailOperation *self,
1666 TnyFolderStore *parent,
1668 CreateFolderUserCallback callback,
1671 ModestMailOperationPrivate *priv;
1673 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1674 g_return_if_fail (name);
1676 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1677 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1678 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1679 g_object_ref (parent) :
1680 modest_tny_folder_get_account (TNY_FOLDER (parent));
1682 /* Check for already existing folder */
1683 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1684 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1685 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1686 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1687 _CS("ckdg_ib_folder_already_exists"));
1691 if (TNY_IS_FOLDER (parent)) {
1692 /* Check folder rules */
1693 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1694 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1695 /* Set status failed and set an error */
1696 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1697 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1698 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1699 _("mail_in_ui_folder_create_error"));
1703 if (!strcmp (name, " ") || strchr (name, '/')) {
1704 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1705 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1706 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1707 _("mail_in_ui_folder_create_error"));
1711 CreateFolderInfo *info;
1713 info = g_slice_new0 (CreateFolderInfo);
1714 info->mail_op = g_object_ref (self);
1715 info->callback = callback;
1716 info->user_data = user_data;
1718 modest_mail_operation_notify_start (self);
1720 /* Create the folder */
1721 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1724 /* Call the user callback anyway */
1726 callback (self, parent, NULL, user_data);
1727 /* Notify about operation end */
1728 modest_mail_operation_notify_end (self);
1733 modest_mail_operation_remove_folder (ModestMailOperation *self,
1735 gboolean remove_to_trash)
1737 TnyAccount *account;
1738 ModestMailOperationPrivate *priv;
1739 ModestTnyFolderRules rules;
1741 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1742 g_return_if_fail (TNY_IS_FOLDER (folder));
1744 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1746 /* Check folder rules */
1747 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1748 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1749 /* Set status failed and set an error */
1750 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1751 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1752 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1753 _("mail_in_ui_folder_delete_error"));
1757 /* Get the account */
1758 account = modest_tny_folder_get_account (folder);
1759 priv->account = g_object_ref(account);
1760 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1762 /* Delete folder or move to trash */
1763 if (remove_to_trash) {
1764 TnyFolder *trash_folder = NULL;
1765 trash_folder = modest_tny_account_get_special_folder (account,
1766 TNY_FOLDER_TYPE_TRASH);
1767 /* TODO: error_handling */
1769 modest_mail_operation_notify_start (self);
1770 modest_mail_operation_xfer_folder (self, folder,
1771 TNY_FOLDER_STORE (trash_folder),
1773 g_object_unref (trash_folder);
1776 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1778 modest_mail_operation_notify_start (self);
1779 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1780 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1783 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1785 g_object_unref (parent);
1787 g_warning ("%s: could not get parent folder", __FUNCTION__);
1789 g_object_unref (G_OBJECT (account));
1792 /* Notify about operation end */
1793 modest_mail_operation_notify_end (self);
1797 transfer_folder_status_cb (GObject *obj,
1801 ModestMailOperation *self;
1802 ModestMailOperationPrivate *priv;
1803 ModestMailOperationState *state;
1804 XFerMsgAsyncHelper *helper;
1806 g_return_if_fail (status != NULL);
1807 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1809 helper = (XFerMsgAsyncHelper *) user_data;
1810 g_return_if_fail (helper != NULL);
1812 self = helper->mail_op;
1813 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1815 priv->done = status->position;
1816 priv->total = status->of_total;
1818 state = modest_mail_operation_clone_state (self);
1820 /* This is not a GDK lock because we are a Tinymail callback
1821 * which is already GDK locked by Tinymail */
1823 /* no gdk_threads_enter (), CHECKED */
1825 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1827 /* no gdk_threads_leave (), CHECKED */
1829 g_slice_free (ModestMailOperationState, state);
1834 transfer_folder_cb (TnyFolder *folder,
1836 TnyFolderStore *into,
1837 TnyFolder *new_folder,
1841 XFerMsgAsyncHelper *helper;
1842 ModestMailOperation *self = NULL;
1843 ModestMailOperationPrivate *priv = NULL;
1845 helper = (XFerMsgAsyncHelper *) user_data;
1846 g_return_if_fail (helper != NULL);
1848 self = helper->mail_op;
1849 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1852 priv->error = g_error_copy (err);
1854 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1855 } else if (cancelled) {
1856 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1857 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1858 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1859 _("Transference of %s was cancelled."),
1860 tny_folder_get_name (folder));
1863 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1866 /* Notify about operation end */
1867 modest_mail_operation_notify_end (self);
1869 /* If user defined callback function was defined, call it */
1870 if (helper->user_callback) {
1872 /* This is not a GDK lock because we are a Tinymail callback
1873 * which is already GDK locked by Tinymail */
1875 /* no gdk_threads_enter (), CHECKED */
1876 helper->user_callback (self, helper->user_data);
1877 /* no gdk_threads_leave () , CHECKED */
1881 g_object_unref (helper->mail_op);
1882 g_slice_free (XFerMsgAsyncHelper, helper);
1887 * This function checks if the new name is a valid name for our local
1888 * folders account. The new name could not be the same than then name
1889 * of any of the mandatory local folders
1891 * We can not rely on tinymail because tinymail does not check the
1892 * name of the virtual folders that the account could have in the case
1893 * that we're doing a rename (because it directly calls Camel which
1894 * knows nothing about our virtual folders).
1896 * In the case of an actual copy/move (i.e. move/copy a folder between
1897 * accounts) tinymail uses the tny_folder_store_create_account which
1898 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1899 * checks the new name of the folder, so this call in that case
1900 * wouldn't be needed. *But* NOTE that if tinymail changes its
1901 * implementation (if folder transfers within the same account is no
1902 * longer implemented as a rename) this call will allow Modest to work
1905 * If the new name is not valid, this function will set the status to
1906 * failed and will set also an error in the mail operation
1909 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1910 TnyFolderStore *into,
1911 const gchar *new_name)
1913 if (TNY_IS_ACCOUNT (into) &&
1914 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1915 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1917 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1918 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1919 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1920 _CS("ckdg_ib_folder_already_exists"));
1927 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1929 TnyFolderStore *parent,
1930 gboolean delete_original,
1931 XferAsyncUserCallback user_callback,
1934 ModestMailOperationPrivate *priv = NULL;
1935 ModestTnyFolderRules parent_rules = 0, rules;
1936 XFerMsgAsyncHelper *helper = NULL;
1937 const gchar *folder_name = NULL;
1938 const gchar *error_msg;
1940 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1941 g_return_if_fail (TNY_IS_FOLDER (folder));
1942 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1944 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1945 folder_name = tny_folder_get_name (folder);
1947 /* Set the error msg */
1948 error_msg = _("mail_in_ui_folder_move_target_error");
1950 /* Get account and set it into mail_operation */
1951 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1952 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1953 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1955 /* Get folder rules */
1956 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1957 if (TNY_IS_FOLDER (parent))
1958 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1960 /* Apply operation constraints */
1961 if ((gpointer) parent == (gpointer) folder ||
1962 (!TNY_IS_FOLDER_STORE (parent)) ||
1963 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1966 } else if (TNY_IS_FOLDER (parent) &&
1967 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1971 } else if (TNY_IS_FOLDER (parent) &&
1972 TNY_IS_FOLDER_STORE (folder) &&
1973 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1974 TNY_FOLDER_STORE (folder))) {
1975 /* Do not move a parent into a child */
1977 } else if (TNY_IS_FOLDER_STORE (parent) &&
1978 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
1979 /* Check that the new folder name is not used by any
1982 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1983 /* Check that the new folder name is not used by any
1984 special local folder */
1987 /* Create the helper */
1988 helper = g_slice_new0 (XFerMsgAsyncHelper);
1989 helper->mail_op = g_object_ref (self);
1990 helper->dest_folder = NULL;
1991 helper->headers = NULL;
1992 helper->user_callback = user_callback;
1993 helper->user_data = user_data;
1995 /* Move/Copy folder */
1996 modest_mail_operation_notify_start (self);
1997 tny_folder_copy_async (folder,
1999 tny_folder_get_name (folder),
2002 transfer_folder_status_cb,
2008 /* Set status failed and set an error */
2009 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2010 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2011 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2014 /* Call the user callback if exists */
2016 user_callback (self, user_data);
2018 /* Notify the queue */
2019 modest_mail_operation_notify_end (self);
2023 modest_mail_operation_rename_folder (ModestMailOperation *self,
2027 ModestMailOperationPrivate *priv;
2028 ModestTnyFolderRules rules;
2029 XFerMsgAsyncHelper *helper;
2031 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2032 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2033 g_return_if_fail (name);
2035 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2037 /* Get account and set it into mail_operation */
2038 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2039 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2041 /* Check folder rules */
2042 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2043 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2044 /* Set status failed and set an error */
2045 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2046 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2047 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2048 _("FIXME: unable to rename"));
2050 /* Notify about operation end */
2051 modest_mail_operation_notify_end (self);
2052 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2053 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2054 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2055 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2056 _("FIXME: unable to rename"));
2057 /* Notify about operation end */
2058 modest_mail_operation_notify_end (self);
2060 TnyFolderStore *into;
2062 into = tny_folder_get_folder_store (folder);
2064 /* Check that the new folder name is not used by any
2065 special local folder */
2066 if (new_name_valid_if_local_account (priv, into, name)) {
2067 /* Create the helper */
2068 helper = g_slice_new0 (XFerMsgAsyncHelper);
2069 helper->mail_op = g_object_ref(self);
2070 helper->dest_folder = NULL;
2071 helper->headers = NULL;
2072 helper->user_callback = NULL;
2073 helper->user_data = NULL;
2075 /* Rename. Camel handles folder subscription/unsubscription */
2076 modest_mail_operation_notify_start (self);
2077 tny_folder_copy_async (folder, into, name, TRUE,
2079 transfer_folder_status_cb,
2082 modest_mail_operation_notify_end (self);
2084 g_object_unref (into);
2088 /* ******************************************************************* */
2089 /* ************************** MSG ACTIONS ************************* */
2090 /* ******************************************************************* */
2093 modest_mail_operation_get_msg (ModestMailOperation *self,
2095 GetMsgAsyncUserCallback user_callback,
2098 GetMsgInfo *helper = NULL;
2100 ModestMailOperationPrivate *priv;
2102 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2103 g_return_if_fail (TNY_IS_HEADER (header));
2105 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2106 folder = tny_header_get_folder (header);
2108 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2112 /* Get account and set it into mail_operation */
2113 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2115 /* Check for cached messages */
2116 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2117 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2119 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2121 /* Create the helper */
2122 helper = g_slice_new0 (GetMsgInfo);
2123 helper->header = g_object_ref (header);
2124 helper->mail_op = g_object_ref (self);
2125 helper->user_callback = user_callback;
2126 helper->user_data = user_data;
2127 helper->destroy_notify = NULL;
2128 helper->last_total_bytes = 0;
2129 helper->sum_total_bytes = 0;
2130 helper->total_bytes = tny_header_get_message_size (header);
2132 modest_mail_operation_notify_start (self);
2134 /* notify about the start of the operation */
2135 ModestMailOperationState *state;
2136 state = modest_mail_operation_clone_state (self);
2139 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2142 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2144 g_object_unref (G_OBJECT (folder));
2148 get_msg_status_cb (GObject *obj,
2152 GetMsgInfo *helper = NULL;
2154 g_return_if_fail (status != NULL);
2155 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2157 helper = (GetMsgInfo *) user_data;
2158 g_return_if_fail (helper != NULL);
2160 /* Notify progress */
2161 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2162 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2166 get_msg_async_cb (TnyFolder *folder,
2172 GetMsgInfo *info = NULL;
2173 ModestMailOperationPrivate *priv = NULL;
2176 info = (GetMsgInfo *) user_data;
2178 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2180 finished = (priv->done == priv->total) ? TRUE : FALSE;
2183 if (canceled || err) {
2184 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2186 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2187 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2190 /* Set the success status before calling the user callback */
2191 if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2192 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2196 /* Call the user callback */
2197 if (info->user_callback)
2198 info->user_callback (info->mail_op, info->header, canceled,
2199 msg, err, info->user_data);
2201 /* Notify about operation end if this is the last callback */
2203 /* Free user data */
2204 if (info->destroy_notify)
2205 info->destroy_notify (info->user_data);
2207 /* Notify about operation end */
2208 modest_mail_operation_notify_end (info->mail_op);
2212 g_object_unref (info->header);
2213 g_object_unref (info->mail_op);
2214 g_slice_free (GetMsgInfo, info);
2218 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2219 TnyList *header_list,
2220 GetMsgAsyncUserCallback user_callback,
2222 GDestroyNotify notify)
2224 ModestMailOperationPrivate *priv = NULL;
2225 gboolean size_ok = TRUE;
2227 TnyIterator *iter = NULL;
2229 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2231 /* Init mail operation */
2232 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2233 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2234 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2236 priv->total = tny_list_get_length(header_list);
2238 /* Get account and set it into mail_operation */
2239 if (tny_list_get_length (header_list) >= 1) {
2240 iter = tny_list_create_iterator (header_list);
2241 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2243 TnyFolder *folder = tny_header_get_folder (header);
2245 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2246 g_object_unref (folder);
2248 g_object_unref (header);
2251 if (tny_list_get_length (header_list) == 1) {
2252 g_object_unref (iter);
2257 /* Get msg size limit */
2258 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2259 MODEST_CONF_MSG_SIZE_LIMIT,
2262 g_clear_error (&(priv->error));
2263 max_size = G_MAXINT;
2265 max_size = max_size * KB;
2268 /* Check message size limits. If there is only one message
2269 always retrieve it */
2271 while (!tny_iterator_is_done (iter) && size_ok) {
2272 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2274 if (tny_header_get_message_size (header) >= max_size)
2276 g_object_unref (header);
2279 tny_iterator_next (iter);
2281 g_object_unref (iter);
2285 const gint msg_list_size = compute_message_list_size (header_list);
2287 modest_mail_operation_notify_start (self);
2288 iter = tny_list_create_iterator (header_list);
2289 while (!tny_iterator_is_done (iter)) {
2290 /* notify about the start of the operation */
2291 ModestMailOperationState *state;
2292 state = modest_mail_operation_clone_state (self);
2295 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2298 GetMsgInfo *msg_info = NULL;
2299 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2300 TnyFolder *folder = tny_header_get_folder (header);
2302 /* Create the message info */
2303 msg_info = g_slice_new0 (GetMsgInfo);
2304 msg_info->mail_op = g_object_ref (self);
2305 msg_info->header = g_object_ref (header);
2306 msg_info->user_callback = user_callback;
2307 msg_info->user_data = user_data;
2308 msg_info->destroy_notify = notify;
2309 msg_info->last_total_bytes = 0;
2310 msg_info->sum_total_bytes = 0;
2311 msg_info->total_bytes = msg_list_size;
2313 /* The callback will call it per each header */
2314 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2316 /* Free and go on */
2317 g_object_unref (header);
2318 g_object_unref (folder);
2319 tny_iterator_next (iter);
2321 g_object_unref (iter);
2323 /* Set status failed and set an error */
2324 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2325 /* FIXME: the error msg is different for pop */
2326 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2327 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2328 _("emev_ni_ui_imap_msg_size_exceed_error"));
2329 /* Remove from queue and free resources */
2330 modest_mail_operation_notify_end (self);
2338 modest_mail_operation_remove_msg (ModestMailOperation *self,
2340 gboolean remove_to_trash /*ignored*/)
2343 ModestMailOperationPrivate *priv;
2345 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2346 g_return_if_fail (TNY_IS_HEADER (header));
2348 if (remove_to_trash)
2349 g_warning ("remove to trash is not implemented");
2351 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2352 folder = tny_header_get_folder (header);
2354 /* Get account and set it into mail_operation */
2355 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2356 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2357 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2359 /* remove message from folder */
2360 tny_folder_remove_msg (folder, header, &(priv->error));
2362 gboolean expunge, leave_on_server;
2363 const gchar *account_name;
2364 TnyAccount *account;
2365 ModestTransportStoreProtocol account_proto;
2367 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2368 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2370 modest_mail_operation_notify_start (self);
2372 /* Get leave on server setting */
2373 account = tny_folder_get_account (folder);
2374 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2376 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2379 account_proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
2381 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2382 modest_tny_folder_is_remote_folder (folder) == FALSE)
2388 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2391 g_object_unref (account);
2397 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2399 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2402 g_object_unref (G_OBJECT (folder));
2404 /* Notify about operation end */
2405 modest_mail_operation_notify_end (self);
2409 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2411 gboolean remove_to_trash /*ignored*/)
2414 ModestMailOperationPrivate *priv;
2415 TnyIterator *iter = NULL;
2416 TnyHeader *header = NULL;
2417 TnyList *remove_headers = NULL;
2418 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2420 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2421 g_return_if_fail (TNY_IS_LIST (headers));
2423 if (remove_to_trash)
2424 g_warning ("remove to trash is not implemented");
2426 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2428 remove_headers = g_object_ref(headers);
2430 /* Get folder from first header and sync it */
2431 iter = tny_list_create_iterator (headers);
2432 header = TNY_HEADER (tny_iterator_get_current (iter));
2433 folder = tny_header_get_folder (header);
2435 /* Don't remove messages that are being sent */
2436 if (modest_tny_folder_is_local_folder (folder)) {
2437 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2439 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2440 TnyTransportAccount *traccount = NULL;
2441 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2442 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2444 ModestTnySendQueueStatus status;
2445 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2446 TnyIterator *iter = tny_list_create_iterator(headers);
2447 g_object_unref(remove_headers);
2448 remove_headers = TNY_LIST(tny_simple_list_new());
2449 while (!tny_iterator_is_done(iter)) {
2451 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2452 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2453 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2454 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2455 tny_list_append(remove_headers, G_OBJECT(hdr));
2457 g_object_unref(hdr);
2459 tny_iterator_next(iter);
2461 g_object_unref(iter);
2462 g_object_unref(traccount);
2466 /* Get account and set it into mail_operation */
2467 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2468 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2469 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2471 /* remove message from folder */
2472 modest_mail_operation_notify_start (self);
2474 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2476 gboolean expunge, leave_on_server;
2477 const gchar *account_name;
2478 TnyAccount *account;
2479 ModestTransportStoreProtocol account_proto;
2481 account = tny_folder_get_account (folder);
2482 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2484 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2487 account_proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
2489 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2490 modest_tny_folder_is_remote_folder (folder) == FALSE)
2496 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2498 g_object_unref (account);
2504 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2506 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2509 g_object_unref (remove_headers);
2510 g_object_unref (header);
2511 g_object_unref (iter);
2512 g_object_unref (G_OBJECT (folder));
2514 /* Notify about operation end */
2515 modest_mail_operation_notify_end (self);
2519 notify_progress_of_multiple_messages (ModestMailOperation *self,
2521 gint *last_total_bytes,
2522 gint *sum_total_bytes,
2524 gboolean increment_done)
2526 ModestMailOperationPrivate *priv;
2527 ModestMailOperationState *state;
2528 gboolean is_num_bytes;
2530 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2532 /* We know that tinymail sends us information about
2533 transferred bytes with this particular message */
2534 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2536 state = modest_mail_operation_clone_state (self);
2537 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2538 /* We know that we're in a different message when the
2539 total number of bytes to transfer is different. Of
2540 course it could fail if we're transferring messages
2541 of the same size, but this is a workarround */
2542 if (status->of_total != *last_total_bytes) {
2543 /* We need to increment the done when there is
2544 no information about each individual
2545 message, we need to do this in message
2546 transfers, and we don't do it for getting
2550 *sum_total_bytes += *last_total_bytes;
2551 *last_total_bytes = status->of_total;
2553 state->bytes_done += status->position + *sum_total_bytes;
2554 state->bytes_total = total_bytes;
2556 /* Notify the status change. Only notify about changes
2557 referred to bytes */
2558 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2562 g_slice_free (ModestMailOperationState, state);
2566 transfer_msgs_status_cb (GObject *obj,
2570 XFerMsgAsyncHelper *helper;
2572 g_return_if_fail (status != NULL);
2573 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2575 helper = (XFerMsgAsyncHelper *) user_data;
2576 g_return_if_fail (helper != NULL);
2578 /* Notify progress */
2579 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2580 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2585 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2587 XFerMsgAsyncHelper *helper;
2588 ModestMailOperation *self;
2589 ModestMailOperationPrivate *priv;
2590 TnyIterator *iter = NULL;
2591 TnyHeader *header = NULL;
2593 helper = (XFerMsgAsyncHelper *) user_data;
2594 self = helper->mail_op;
2596 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2599 priv->error = g_error_copy (err);
2601 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2602 } else if (cancelled) {
2603 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2604 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2605 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2606 _("Error trying to refresh the contents of %s"),
2607 tny_folder_get_name (folder));
2610 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2612 /* Update folder counts */
2613 tny_folder_poke_status (folder);
2614 tny_folder_poke_status (helper->dest_folder);
2618 /* Mark headers as deleted and seen */
2619 if ((helper->delete) &&
2620 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2621 iter = tny_list_create_iterator (helper->headers);
2622 while (!tny_iterator_is_done (iter)) {
2623 header = TNY_HEADER (tny_iterator_get_current (iter));
2624 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2625 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2626 g_object_unref (header);
2628 tny_iterator_next (iter);
2634 /* Notify about operation end */
2635 modest_mail_operation_notify_end (self);
2637 /* If user defined callback function was defined, call it */
2638 if (helper->user_callback) {
2639 /* This is not a GDK lock because we are a Tinymail callback and
2640 * Tinymail already acquires the Gdk lock */
2642 /* no gdk_threads_enter (), CHECKED */
2643 helper->user_callback (self, helper->user_data);
2644 /* no gdk_threads_leave (), CHECKED */
2648 if (helper->headers)
2649 g_object_unref (helper->headers);
2650 if (helper->dest_folder)
2651 g_object_unref (helper->dest_folder);
2652 if (helper->mail_op)
2653 g_object_unref (helper->mail_op);
2655 g_object_unref (folder);
2657 g_object_unref (iter);
2658 g_slice_free (XFerMsgAsyncHelper, helper);
2662 compute_message_list_size (TnyList *headers)
2667 iter = tny_list_create_iterator (headers);
2668 while (!tny_iterator_is_done (iter)) {
2669 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2670 size += tny_header_get_message_size (header);
2671 g_object_unref (header);
2672 tny_iterator_next (iter);
2674 g_object_unref (iter);
2680 compute_message_array_size (GPtrArray *headers)
2685 for (i = 0; i < headers->len; i++) {
2686 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2687 size += tny_header_get_message_size (header);
2695 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2698 gboolean delete_original,
2699 XferAsyncUserCallback user_callback,
2702 ModestMailOperationPrivate *priv = NULL;
2703 TnyIterator *iter = NULL;
2704 TnyFolder *src_folder = NULL;
2705 XFerMsgAsyncHelper *helper = NULL;
2706 TnyHeader *header = NULL;
2707 ModestTnyFolderRules rules = 0;
2709 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2710 g_return_if_fail (headers && TNY_IS_LIST (headers));
2711 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2713 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2714 priv->total = tny_list_get_length (headers);
2716 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2717 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2719 /* Apply folder rules */
2720 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2721 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2722 /* Set status failed and set an error */
2723 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2724 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2725 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2726 _CS("ckct_ib_unable_to_paste_here"));
2727 /* Notify the queue */
2728 modest_mail_operation_notify_end (self);
2732 /* Get source folder */
2733 iter = tny_list_create_iterator (headers);
2734 header = TNY_HEADER (tny_iterator_get_current (iter));
2736 src_folder = tny_header_get_folder (header);
2737 g_object_unref (header);
2739 g_object_unref (iter);
2741 if (src_folder == NULL) {
2742 /* Notify the queue */
2743 modest_mail_operation_notify_end (self);
2745 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2750 /* Check folder source and destination */
2751 if (src_folder == folder) {
2752 /* Set status failed and set an error */
2753 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2754 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2755 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2756 _("mail_in_ui_folder_copy_target_error"));
2758 /* Notify the queue */
2759 modest_mail_operation_notify_end (self);
2762 g_object_unref (src_folder);
2766 /* Create the helper */
2767 helper = g_slice_new0 (XFerMsgAsyncHelper);
2768 helper->mail_op = g_object_ref(self);
2769 helper->dest_folder = g_object_ref(folder);
2770 helper->headers = g_object_ref(headers);
2771 helper->user_callback = user_callback;
2772 helper->user_data = user_data;
2773 helper->delete = delete_original;
2774 helper->last_total_bytes = 0;
2775 helper->sum_total_bytes = 0;
2776 helper->total_bytes = compute_message_list_size (headers);
2778 /* Get account and set it into mail_operation */
2779 priv->account = modest_tny_folder_get_account (src_folder);
2781 /* Transfer messages */
2782 modest_mail_operation_notify_start (self);
2783 tny_folder_transfer_msgs_async (src_folder,
2788 transfer_msgs_status_cb,
2794 on_refresh_folder (TnyFolder *folder,
2799 RefreshAsyncHelper *helper = NULL;
2800 ModestMailOperation *self = NULL;
2801 ModestMailOperationPrivate *priv = NULL;
2803 helper = (RefreshAsyncHelper *) user_data;
2804 self = helper->mail_op;
2805 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2807 g_return_if_fail(priv!=NULL);
2810 priv->error = g_error_copy (error);
2811 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2816 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2817 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2818 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2819 _("Error trying to refresh the contents of %s"),
2820 tny_folder_get_name (folder));
2824 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2827 /* Call user defined callback, if it exists */
2828 if (helper->user_callback) {
2830 /* This is not a GDK lock because we are a Tinymail callback and
2831 * Tinymail already acquires the Gdk lock */
2832 helper->user_callback (self, folder, helper->user_data);
2836 g_slice_free (RefreshAsyncHelper, helper);
2838 /* Notify about operation end */
2839 modest_mail_operation_notify_end (self);
2840 g_object_unref(self);
2844 on_refresh_folder_status_update (GObject *obj,
2848 RefreshAsyncHelper *helper = NULL;
2849 ModestMailOperation *self = NULL;
2850 ModestMailOperationPrivate *priv = NULL;
2851 ModestMailOperationState *state;
2853 g_return_if_fail (user_data != NULL);
2854 g_return_if_fail (status != NULL);
2855 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2857 helper = (RefreshAsyncHelper *) user_data;
2858 self = helper->mail_op;
2859 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2861 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2863 priv->done = status->position;
2864 priv->total = status->of_total;
2866 state = modest_mail_operation_clone_state (self);
2868 /* This is not a GDK lock because we are a Tinymail callback and
2869 * Tinymail already acquires the Gdk lock */
2870 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2872 g_slice_free (ModestMailOperationState, state);
2876 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2878 RefreshAsyncUserCallback user_callback,
2881 ModestMailOperationPrivate *priv = NULL;
2882 RefreshAsyncHelper *helper = NULL;
2884 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2886 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2888 /* Get account and set it into mail_operation */
2889 priv->account = modest_tny_folder_get_account (folder);
2890 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2892 /* Create the helper */
2893 helper = g_slice_new0 (RefreshAsyncHelper);
2894 helper->mail_op = g_object_ref(self);
2895 helper->user_callback = user_callback;
2896 helper->user_data = user_data;
2898 /* Refresh the folder. TODO: tinymail could issue a status
2899 updates before the callback call then this could happen. We
2900 must review the design */
2901 modest_mail_operation_notify_start (self);
2903 /* notify that the operation was started */
2904 ModestMailOperationState *state;
2905 state = modest_mail_operation_clone_state (self);
2908 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2911 tny_folder_refresh_async (folder,
2913 on_refresh_folder_status_update,
2919 modest_mail_operation_notify_start (ModestMailOperation *self)
2921 ModestMailOperationPrivate *priv = NULL;
2923 g_return_if_fail (self);
2925 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2927 /* Ensure that all the fields are filled correctly */
2928 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
2930 /* Notify the observers about the mail operation. We do not
2931 wrapp this emission because we assume that this function is
2932 always called from within the main lock */
2933 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
2938 * It's used by the mail operation queue to notify the observers
2939 * attached to that signal that the operation finished. We need to use
2940 * that because tinymail does not give us the progress of a given
2941 * operation when it finishes (it directly calls the operation
2945 modest_mail_operation_notify_end (ModestMailOperation *self)
2947 ModestMailOperationPrivate *priv = NULL;
2949 g_return_if_fail (self);
2951 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2953 /* Notify the observers about the mail operation end. We do
2954 not wrapp this emission because we assume that this
2955 function is always called from within the main lock */
2956 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
2958 /* Remove the error user data */
2959 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
2960 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
2964 modest_mail_operation_get_account (ModestMailOperation *self)
2966 ModestMailOperationPrivate *priv = NULL;
2968 g_return_val_if_fail (self, NULL);
2970 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2972 return (priv->account) ? g_object_ref (priv->account) : NULL;
2976 modest_mail_operation_noop (ModestMailOperation *self)
2978 ModestMailOperationPrivate *priv = NULL;
2980 g_return_if_fail (self);
2982 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2983 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2984 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2988 /* This mail operation does nothing actually */
2989 modest_mail_operation_notify_start (self);
2990 modest_mail_operation_notify_end (self);