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 if (!(priv->error)) {
1055 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1056 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1057 "modest: failed to create a new msg\n");
1060 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1061 TNY_FOLDER_TYPE_DRAFTS);
1062 if (!drafts && !(priv->error)) {
1063 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1064 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1065 "modest: failed to create a new msg\n");
1070 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1071 cb_info->transport_account = g_object_ref(info->transport_account);
1072 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1073 cb_info->callback = info->callback;
1074 cb_info->user_data = info->user_data;
1075 cb_info->drafts = g_object_ref(drafts);
1076 cb_info->msg = g_object_ref(msg);
1077 cb_info->mailop = g_object_ref(self);
1078 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1081 /* Call the user callback */
1082 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1084 info->callback (self, msg, info->user_data);
1085 modest_mail_operation_notify_end (self);
1089 g_object_unref (G_OBJECT(drafts));
1090 if (info->draft_msg)
1091 g_object_unref (G_OBJECT (info->draft_msg));
1092 if (info->transport_account)
1093 g_object_unref (G_OBJECT(info->transport_account));
1094 g_slice_free (SaveToDraftsInfo, info);
1098 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1099 TnyTransportAccount *transport_account,
1101 const gchar *from, const gchar *to,
1102 const gchar *cc, const gchar *bcc,
1103 const gchar *subject, const gchar *plain_body,
1104 const gchar *html_body,
1105 const GList *attachments_list,
1106 const GList *images_list,
1107 TnyHeaderFlags priority_flags,
1108 SaveToDraftstCallback callback,
1111 ModestMailOperationPrivate *priv = NULL;
1112 SaveToDraftsInfo *info = NULL;
1114 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1115 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1117 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1119 /* Get account and set it into mail_operation */
1120 priv->account = g_object_ref (transport_account);
1121 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1123 info = g_slice_new0 (SaveToDraftsInfo);
1124 info->transport_account = g_object_ref (transport_account);
1125 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1126 info->callback = callback;
1127 info->user_data = user_data;
1129 modest_mail_operation_notify_start (self);
1130 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1131 attachments_list, images_list, priority_flags,
1132 modest_mail_operation_save_to_drafts_cb, info);
1137 ModestMailOperation *mail_op;
1138 TnyMimePart *mime_part;
1140 GetMimePartSizeCallback callback;
1142 } GetMimePartSizeInfo;
1144 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1145 /* We use this folder observer to track the headers that have been
1146 * added to a folder */
1149 TnyList *new_headers;
1150 } InternalFolderObserver;
1153 GObjectClass parent;
1154 } InternalFolderObserverClass;
1156 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1158 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1159 internal_folder_observer,
1161 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1165 foreach_add_item (gpointer header, gpointer user_data)
1167 tny_list_prepend (TNY_LIST (user_data),
1168 g_object_ref (G_OBJECT (header)));
1171 /* This is the method that looks for new messages in a folder */
1173 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1175 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1177 TnyFolderChangeChanged changed;
1179 changed = tny_folder_change_get_changed (change);
1181 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1184 /* Get added headers */
1185 list = tny_simple_list_new ();
1186 tny_folder_change_get_added_headers (change, list);
1188 /* Add them to the folder observer */
1189 tny_list_foreach (list, foreach_add_item,
1190 derived->new_headers);
1192 g_object_unref (G_OBJECT (list));
1197 internal_folder_observer_init (InternalFolderObserver *self)
1199 self->new_headers = tny_simple_list_new ();
1202 internal_folder_observer_finalize (GObject *object)
1204 InternalFolderObserver *self;
1206 self = (InternalFolderObserver *) object;
1207 g_object_unref (self->new_headers);
1209 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1212 tny_folder_observer_init (TnyFolderObserverIface *iface)
1214 iface->update_func = internal_folder_observer_update;
1217 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1219 GObjectClass *object_class;
1221 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1222 object_class = (GObjectClass*) klass;
1223 object_class->finalize = internal_folder_observer_finalize;
1228 ModestMailOperation *mail_op;
1229 gchar *account_name;
1230 UpdateAccountCallback callback;
1235 TnyFolderObserver *inbox_observer;
1236 RetrieveAllCallback retrieve_all_cb;
1237 } UpdateAccountInfo;
1241 destroy_update_account_info (UpdateAccountInfo *info)
1243 g_free (info->account_name);
1244 g_object_unref (info->folders);
1245 g_object_unref (info->mail_op);
1246 g_slice_free (UpdateAccountInfo, info);
1250 update_account_get_msg_async_cb (TnyFolder *folder,
1256 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1258 /* Just delete the helper. Don't do anything with the new
1259 msg. There is also no need to check for errors */
1260 g_object_unref (msg_info->mail_op);
1261 g_object_unref (msg_info->header);
1262 g_slice_free (GetMsgInfo, msg_info);
1267 inbox_refreshed_cb (TnyFolder *inbox,
1272 UpdateAccountInfo *info;
1273 ModestMailOperationPrivate *priv;
1274 TnyIterator *new_headers_iter;
1275 GPtrArray *new_headers_array = NULL;
1276 gint max_size, retrieve_limit, i;
1277 ModestAccountMgr *mgr;
1278 ModestAccountRetrieveType retrieve_type;
1279 TnyList *new_headers = NULL;
1280 gboolean headers_only, ignore_limit;
1281 TnyTransportAccount *transport_account;
1282 ModestTnySendQueue *send_queue;
1284 info = (UpdateAccountInfo *) user_data;
1285 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1286 mgr = modest_runtime_get_account_mgr ();
1288 if (canceled || err || !inbox) {
1289 /* Try to send anyway */
1293 /* Get the message max size */
1294 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1295 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1297 max_size = G_MAXINT;
1299 max_size = max_size * KB;
1301 /* Create the new headers array. We need it to sort the
1302 new headers by date */
1303 new_headers_array = g_ptr_array_new ();
1304 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1305 while (!tny_iterator_is_done (new_headers_iter)) {
1306 TnyHeader *header = NULL;
1308 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1309 /* Apply per-message size limits */
1310 if (tny_header_get_message_size (header) < max_size)
1311 g_ptr_array_add (new_headers_array, g_object_ref (header));
1313 g_object_unref (header);
1314 tny_iterator_next (new_headers_iter);
1316 g_object_unref (new_headers_iter);
1317 tny_folder_remove_observer (inbox, info->inbox_observer);
1318 g_object_unref (info->inbox_observer);
1319 info->inbox_observer = NULL;
1321 /* Update the last updated key, even if we don't have to get new headers */
1322 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1324 if (new_headers_array->len == 0)
1327 /* Get per-account message amount retrieval limit */
1328 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1329 if (retrieve_limit == 0)
1330 retrieve_limit = G_MAXINT;
1332 /* Get per-account retrieval type */
1333 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1334 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1337 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1339 /* Ask the users if they want to retrieve all the messages
1340 even though the limit was exceeded */
1341 ignore_limit = FALSE;
1342 if (new_headers_array->len > retrieve_limit) {
1343 /* Ask the user if a callback has been specified and
1344 if the mail operation has a source (this means that
1345 was invoked by the user and not automatically by a
1347 if (info->retrieve_all_cb && priv->source)
1348 ignore_limit = info->retrieve_all_cb (priv->source,
1349 new_headers_array->len,
1353 if (!headers_only) {
1355 const gint msg_list_size = compute_message_array_size (new_headers_array);
1359 priv->total = new_headers_array->len;
1361 priv->total = MIN (new_headers_array->len, retrieve_limit);
1362 while (msg_num < priv->total) {
1363 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1364 TnyFolder *folder = tny_header_get_folder (header);
1365 GetMsgInfo *msg_info;
1367 /* Create the message info */
1368 msg_info = g_slice_new0 (GetMsgInfo);
1369 msg_info->mail_op = g_object_ref (info->mail_op);
1370 msg_info->header = g_object_ref (header);
1371 msg_info->total_bytes = msg_list_size;
1373 /* Get message in an async way */
1374 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1375 get_msg_status_cb, msg_info);
1377 g_object_unref (folder);
1383 /* Copy the headers to a list and free the array */
1384 new_headers = tny_simple_list_new ();
1385 for (i=0; i < new_headers_array->len; i++) {
1386 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1387 tny_list_append (new_headers, G_OBJECT (header));
1389 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1390 g_ptr_array_free (new_headers_array, FALSE);
1397 /* Get the transport account */
1398 transport_account = (TnyTransportAccount *)
1399 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1400 info->account_name);
1403 send_queue = modest_runtime_get_send_queue (transport_account);
1404 modest_tny_send_queue_try_to_send (send_queue);
1406 /* Check if the operation was a success */
1408 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1410 /* Set the account back to not busy */
1411 modest_account_mgr_set_account_busy (mgr, info->account_name, FALSE);
1413 /* Call the user callback */
1415 info->callback (info->mail_op, new_headers, info->user_data);
1417 /* Notify about operation end */
1418 modest_mail_operation_notify_end (info->mail_op);
1422 g_object_unref (new_headers);
1423 destroy_update_account_info (info);
1427 recurse_folders_async_cb (TnyFolderStore *folder_store,
1433 UpdateAccountInfo *info;
1434 ModestMailOperationPrivate *priv;
1436 info = (UpdateAccountInfo *) user_data;
1437 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1439 if (err || canceled) {
1440 /* Try to continue anyway */
1442 TnyIterator *iter = tny_list_create_iterator (list);
1443 while (!tny_iterator_is_done (iter)) {
1444 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1445 TnyList *folders = tny_simple_list_new ();
1447 /* Add to the list of all folders */
1448 tny_list_append (info->folders, (GObject *) folder);
1450 /* Add pending call */
1451 info->pending_calls++;
1453 tny_folder_store_get_folders_async (folder, folders, NULL,
1454 recurse_folders_async_cb,
1457 g_object_unref (G_OBJECT (folder));
1459 tny_iterator_next (iter);
1461 g_object_unref (G_OBJECT (iter));
1462 g_object_unref (G_OBJECT (list));
1465 /* Remove my own pending call */
1466 info->pending_calls--;
1468 /* This means that we have all the folders */
1469 if (info->pending_calls == 0) {
1470 TnyIterator *iter_all_folders;
1471 TnyFolder *inbox = NULL;
1473 iter_all_folders = tny_list_create_iterator (info->folders);
1475 /* Do a poke status over all folders */
1476 while (!tny_iterator_is_done (iter_all_folders) &&
1477 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1478 TnyFolder *folder = NULL;
1480 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1482 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1483 /* Get a reference to the INBOX */
1484 inbox = g_object_ref (folder);
1486 /* Issue a poke status over the folder */
1488 tny_folder_poke_status (folder);
1491 /* Free and go to next */
1492 g_object_unref (folder);
1493 tny_iterator_next (iter_all_folders);
1495 g_object_unref (iter_all_folders);
1497 /* Refresh the INBOX */
1499 /* Refresh the folder. Our observer receives
1500 * the new emails during folder refreshes, so
1501 * we can use observer->new_headers
1503 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1504 tny_folder_add_observer (inbox, info->inbox_observer);
1506 /* Refresh the INBOX */
1507 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1508 g_object_unref (inbox);
1510 /* We could not perform the inbox refresh but
1511 we'll try to send mails anyway */
1512 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1518 modest_mail_operation_update_account (ModestMailOperation *self,
1519 const gchar *account_name,
1521 RetrieveAllCallback retrieve_all_cb,
1522 UpdateAccountCallback callback,
1525 UpdateAccountInfo *info = NULL;
1526 ModestMailOperationPrivate *priv = NULL;
1527 ModestTnyAccountStore *account_store = NULL;
1528 TnyStoreAccount *store_account = NULL;
1531 /* Init mail operation */
1532 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1535 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1536 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1538 /* Get the store account */
1539 account_store = modest_runtime_get_account_store ();
1540 store_account = (TnyStoreAccount *)
1541 modest_tny_account_store_get_server_account (account_store,
1543 TNY_ACCOUNT_TYPE_STORE);
1544 priv->account = g_object_ref (store_account);
1546 /* Create the helper object */
1547 info = g_slice_new0 (UpdateAccountInfo);
1548 info->pending_calls = 1;
1549 info->folders = tny_simple_list_new ();
1550 info->mail_op = g_object_ref (self);
1551 info->poke_all = poke_all;
1552 info->account_name = g_strdup (account_name);
1553 info->callback = callback;
1554 info->user_data = user_data;
1555 info->retrieve_all_cb = retrieve_all_cb;
1557 /* Set account busy */
1558 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1559 modest_mail_operation_notify_start (self);
1561 /* notify about the start of the operation */
1562 ModestMailOperationState *state;
1563 state = modest_mail_operation_clone_state (self);
1567 /* Start notifying progress */
1568 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
1570 g_slice_free (ModestMailOperationState, state);
1572 /* Get all folders and continue in the callback */
1573 folders = tny_simple_list_new ();
1574 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (store_account),
1576 recurse_folders_async_cb,
1581 * Used to notify the queue from the main
1582 * loop. We call it inside an idle call to achieve that
1585 idle_notify_queue (gpointer data)
1587 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1589 gdk_threads_enter ();
1590 modest_mail_operation_notify_end (mail_op);
1591 gdk_threads_leave ();
1592 g_object_unref (mail_op);
1598 compare_headers_by_date (gconstpointer a,
1601 TnyHeader **header1, **header2;
1602 time_t sent1, sent2;
1604 header1 = (TnyHeader **) a;
1605 header2 = (TnyHeader **) b;
1607 sent1 = tny_header_get_date_sent (*header1);
1608 sent2 = tny_header_get_date_sent (*header2);
1610 /* We want the most recent ones (greater time_t) at the
1619 /* ******************************************************************* */
1620 /* ************************** STORE ACTIONS ************************* */
1621 /* ******************************************************************* */
1624 ModestMailOperation *mail_op;
1625 CreateFolderUserCallback callback;
1631 create_folder_cb (TnyFolderStore *parent_folder,
1633 TnyFolder *new_folder,
1637 ModestMailOperationPrivate *priv;
1638 CreateFolderInfo *info;
1640 info = (CreateFolderInfo *) user_data;
1641 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1643 if (canceled || err) {
1644 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1646 priv->error = g_error_copy (err);
1648 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1649 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1652 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1655 /* The user will unref the new_folder */
1657 info->callback (info->mail_op, parent_folder,
1658 new_folder, info->user_data);
1660 /* Notify about operation end */
1661 modest_mail_operation_notify_end (info->mail_op);
1664 g_object_unref (info->mail_op);
1665 g_slice_free (CreateFolderInfo, info);
1669 modest_mail_operation_create_folder (ModestMailOperation *self,
1670 TnyFolderStore *parent,
1672 CreateFolderUserCallback callback,
1675 ModestMailOperationPrivate *priv;
1677 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1678 g_return_if_fail (name);
1680 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1681 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1682 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1683 g_object_ref (parent) :
1684 modest_tny_folder_get_account (TNY_FOLDER (parent));
1686 /* Check for already existing folder */
1687 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1688 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1689 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1690 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1691 _CS("ckdg_ib_folder_already_exists"));
1695 if (TNY_IS_FOLDER (parent)) {
1696 /* Check folder rules */
1697 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1698 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1699 /* Set status failed and set an error */
1700 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1701 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1702 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1703 _("mail_in_ui_folder_create_error"));
1707 if (!strcmp (name, " ") || strchr (name, '/')) {
1708 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1709 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1710 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1711 _("mail_in_ui_folder_create_error"));
1715 CreateFolderInfo *info;
1717 info = g_slice_new0 (CreateFolderInfo);
1718 info->mail_op = g_object_ref (self);
1719 info->callback = callback;
1720 info->user_data = user_data;
1722 modest_mail_operation_notify_start (self);
1724 /* Create the folder */
1725 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1728 /* Call the user callback anyway */
1730 callback (self, parent, NULL, user_data);
1731 /* Notify about operation end */
1732 modest_mail_operation_notify_end (self);
1737 modest_mail_operation_remove_folder (ModestMailOperation *self,
1739 gboolean remove_to_trash)
1741 TnyAccount *account;
1742 ModestMailOperationPrivate *priv;
1743 ModestTnyFolderRules rules;
1745 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1746 g_return_if_fail (TNY_IS_FOLDER (folder));
1748 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1750 /* Check folder rules */
1751 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1752 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1753 /* Set status failed and set an error */
1754 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1755 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1756 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1757 _("mail_in_ui_folder_delete_error"));
1761 /* Get the account */
1762 account = modest_tny_folder_get_account (folder);
1763 priv->account = g_object_ref(account);
1764 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1766 /* Delete folder or move to trash */
1767 if (remove_to_trash) {
1768 TnyFolder *trash_folder = NULL;
1769 trash_folder = modest_tny_account_get_special_folder (account,
1770 TNY_FOLDER_TYPE_TRASH);
1771 /* TODO: error_handling */
1773 modest_mail_operation_notify_start (self);
1774 modest_mail_operation_xfer_folder (self, folder,
1775 TNY_FOLDER_STORE (trash_folder),
1777 g_object_unref (trash_folder);
1780 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1782 modest_mail_operation_notify_start (self);
1783 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1784 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1787 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1789 g_object_unref (parent);
1791 g_warning ("%s: could not get parent folder", __FUNCTION__);
1793 g_object_unref (G_OBJECT (account));
1796 /* Notify about operation end */
1797 modest_mail_operation_notify_end (self);
1801 transfer_folder_status_cb (GObject *obj,
1805 ModestMailOperation *self;
1806 ModestMailOperationPrivate *priv;
1807 ModestMailOperationState *state;
1808 XFerMsgAsyncHelper *helper;
1810 g_return_if_fail (status != NULL);
1811 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1813 helper = (XFerMsgAsyncHelper *) user_data;
1814 g_return_if_fail (helper != NULL);
1816 self = helper->mail_op;
1817 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1819 priv->done = status->position;
1820 priv->total = status->of_total;
1822 state = modest_mail_operation_clone_state (self);
1824 /* This is not a GDK lock because we are a Tinymail callback
1825 * which is already GDK locked by Tinymail */
1827 /* no gdk_threads_enter (), CHECKED */
1829 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1831 /* no gdk_threads_leave (), CHECKED */
1833 g_slice_free (ModestMailOperationState, state);
1838 transfer_folder_cb (TnyFolder *folder,
1840 TnyFolderStore *into,
1841 TnyFolder *new_folder,
1845 XFerMsgAsyncHelper *helper;
1846 ModestMailOperation *self = NULL;
1847 ModestMailOperationPrivate *priv = NULL;
1849 helper = (XFerMsgAsyncHelper *) user_data;
1850 g_return_if_fail (helper != NULL);
1852 self = helper->mail_op;
1853 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1856 priv->error = g_error_copy (err);
1858 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1859 } else if (cancelled) {
1860 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1861 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1862 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1863 _("Transference of %s was cancelled."),
1864 tny_folder_get_name (folder));
1867 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1870 /* Notify about operation end */
1871 modest_mail_operation_notify_end (self);
1873 /* If user defined callback function was defined, call it */
1874 if (helper->user_callback) {
1876 /* This is not a GDK lock because we are a Tinymail callback
1877 * which is already GDK locked by Tinymail */
1879 /* no gdk_threads_enter (), CHECKED */
1880 helper->user_callback (self, helper->user_data);
1881 /* no gdk_threads_leave () , CHECKED */
1885 g_object_unref (helper->mail_op);
1886 g_slice_free (XFerMsgAsyncHelper, helper);
1891 * This function checks if the new name is a valid name for our local
1892 * folders account. The new name could not be the same than then name
1893 * of any of the mandatory local folders
1895 * We can not rely on tinymail because tinymail does not check the
1896 * name of the virtual folders that the account could have in the case
1897 * that we're doing a rename (because it directly calls Camel which
1898 * knows nothing about our virtual folders).
1900 * In the case of an actual copy/move (i.e. move/copy a folder between
1901 * accounts) tinymail uses the tny_folder_store_create_account which
1902 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1903 * checks the new name of the folder, so this call in that case
1904 * wouldn't be needed. *But* NOTE that if tinymail changes its
1905 * implementation (if folder transfers within the same account is no
1906 * longer implemented as a rename) this call will allow Modest to work
1909 * If the new name is not valid, this function will set the status to
1910 * failed and will set also an error in the mail operation
1913 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1914 TnyFolderStore *into,
1915 const gchar *new_name)
1917 if (TNY_IS_ACCOUNT (into) &&
1918 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1919 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1921 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1922 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1923 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1924 _CS("ckdg_ib_folder_already_exists"));
1931 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1933 TnyFolderStore *parent,
1934 gboolean delete_original,
1935 XferAsyncUserCallback user_callback,
1938 ModestMailOperationPrivate *priv = NULL;
1939 ModestTnyFolderRules parent_rules = 0, rules;
1940 XFerMsgAsyncHelper *helper = NULL;
1941 const gchar *folder_name = NULL;
1942 const gchar *error_msg;
1944 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1945 g_return_if_fail (TNY_IS_FOLDER (folder));
1946 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1948 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1949 folder_name = tny_folder_get_name (folder);
1951 /* Set the error msg */
1952 error_msg = _("mail_in_ui_folder_move_target_error");
1954 /* Get account and set it into mail_operation */
1955 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1956 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1957 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1959 /* Get folder rules */
1960 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1961 if (TNY_IS_FOLDER (parent))
1962 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1964 /* Apply operation constraints */
1965 if ((gpointer) parent == (gpointer) folder ||
1966 (!TNY_IS_FOLDER_STORE (parent)) ||
1967 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1970 } else if (TNY_IS_FOLDER (parent) &&
1971 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1975 } else if (TNY_IS_FOLDER (parent) &&
1976 TNY_IS_FOLDER_STORE (folder) &&
1977 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1978 TNY_FOLDER_STORE (folder))) {
1979 /* Do not move a parent into a child */
1981 } else if (TNY_IS_FOLDER_STORE (parent) &&
1982 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
1983 /* Check that the new folder name is not used by any
1986 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1987 /* Check that the new folder name is not used by any
1988 special local folder */
1991 /* Create the helper */
1992 helper = g_slice_new0 (XFerMsgAsyncHelper);
1993 helper->mail_op = g_object_ref (self);
1994 helper->dest_folder = NULL;
1995 helper->headers = NULL;
1996 helper->user_callback = user_callback;
1997 helper->user_data = user_data;
1999 /* Move/Copy folder */
2000 modest_mail_operation_notify_start (self);
2001 tny_folder_copy_async (folder,
2003 tny_folder_get_name (folder),
2006 transfer_folder_status_cb,
2012 /* Set status failed and set an error */
2013 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2014 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2015 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2018 /* Call the user callback if exists */
2020 user_callback (self, user_data);
2022 /* Notify the queue */
2023 modest_mail_operation_notify_end (self);
2027 modest_mail_operation_rename_folder (ModestMailOperation *self,
2031 ModestMailOperationPrivate *priv;
2032 ModestTnyFolderRules rules;
2033 XFerMsgAsyncHelper *helper;
2035 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2036 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2037 g_return_if_fail (name);
2039 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2041 /* Get account and set it into mail_operation */
2042 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2043 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2045 /* Check folder rules */
2046 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2047 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2048 /* Set status failed and set an error */
2049 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2050 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2051 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2052 _("FIXME: unable to rename"));
2054 /* Notify about operation end */
2055 modest_mail_operation_notify_end (self);
2056 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2057 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2058 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2059 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2060 _("FIXME: unable to rename"));
2061 /* Notify about operation end */
2062 modest_mail_operation_notify_end (self);
2064 TnyFolderStore *into;
2066 into = tny_folder_get_folder_store (folder);
2068 /* Check that the new folder name is not used by any
2069 special local folder */
2070 if (new_name_valid_if_local_account (priv, into, name)) {
2071 /* Create the helper */
2072 helper = g_slice_new0 (XFerMsgAsyncHelper);
2073 helper->mail_op = g_object_ref(self);
2074 helper->dest_folder = NULL;
2075 helper->headers = NULL;
2076 helper->user_callback = NULL;
2077 helper->user_data = NULL;
2079 /* Rename. Camel handles folder subscription/unsubscription */
2080 modest_mail_operation_notify_start (self);
2081 tny_folder_copy_async (folder, into, name, TRUE,
2083 transfer_folder_status_cb,
2086 modest_mail_operation_notify_end (self);
2088 g_object_unref (into);
2092 /* ******************************************************************* */
2093 /* ************************** MSG ACTIONS ************************* */
2094 /* ******************************************************************* */
2097 modest_mail_operation_get_msg (ModestMailOperation *self,
2099 GetMsgAsyncUserCallback user_callback,
2102 GetMsgInfo *helper = NULL;
2104 ModestMailOperationPrivate *priv;
2106 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2107 g_return_if_fail (TNY_IS_HEADER (header));
2109 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2110 folder = tny_header_get_folder (header);
2112 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2116 /* Get account and set it into mail_operation */
2117 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2119 /* Check for cached messages */
2120 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2121 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2123 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2125 /* Create the helper */
2126 helper = g_slice_new0 (GetMsgInfo);
2127 helper->header = g_object_ref (header);
2128 helper->mail_op = g_object_ref (self);
2129 helper->user_callback = user_callback;
2130 helper->user_data = user_data;
2131 helper->destroy_notify = NULL;
2132 helper->last_total_bytes = 0;
2133 helper->sum_total_bytes = 0;
2134 helper->total_bytes = tny_header_get_message_size (header);
2136 modest_mail_operation_notify_start (self);
2138 /* notify about the start of the operation */
2139 ModestMailOperationState *state;
2140 state = modest_mail_operation_clone_state (self);
2143 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2146 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2148 g_object_unref (G_OBJECT (folder));
2152 get_msg_status_cb (GObject *obj,
2156 GetMsgInfo *helper = NULL;
2158 g_return_if_fail (status != NULL);
2159 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2161 helper = (GetMsgInfo *) user_data;
2162 g_return_if_fail (helper != NULL);
2164 /* Notify progress */
2165 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2166 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2170 get_msg_async_cb (TnyFolder *folder,
2176 GetMsgInfo *info = NULL;
2177 ModestMailOperationPrivate *priv = NULL;
2180 info = (GetMsgInfo *) user_data;
2182 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2184 finished = (priv->done == priv->total) ? TRUE : FALSE;
2187 if (canceled || err) {
2188 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2190 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2191 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2194 /* Set the success status before calling the user callback */
2195 if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2196 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2200 /* Call the user callback */
2201 if (info->user_callback)
2202 info->user_callback (info->mail_op, info->header, canceled,
2203 msg, err, info->user_data);
2205 /* Notify about operation end if this is the last callback */
2207 /* Free user data */
2208 if (info->destroy_notify)
2209 info->destroy_notify (info->user_data);
2211 /* Notify about operation end */
2212 modest_mail_operation_notify_end (info->mail_op);
2216 g_object_unref (info->header);
2217 g_object_unref (info->mail_op);
2218 g_slice_free (GetMsgInfo, info);
2222 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2223 TnyList *header_list,
2224 GetMsgAsyncUserCallback user_callback,
2226 GDestroyNotify notify)
2228 ModestMailOperationPrivate *priv = NULL;
2229 gboolean size_ok = TRUE;
2231 TnyIterator *iter = NULL;
2233 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2235 /* Init mail operation */
2236 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2237 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2238 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2240 priv->total = tny_list_get_length(header_list);
2242 /* Get account and set it into mail_operation */
2243 if (tny_list_get_length (header_list) >= 1) {
2244 iter = tny_list_create_iterator (header_list);
2245 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2247 TnyFolder *folder = tny_header_get_folder (header);
2249 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2250 g_object_unref (folder);
2252 g_object_unref (header);
2255 if (tny_list_get_length (header_list) == 1) {
2256 g_object_unref (iter);
2261 /* Get msg size limit */
2262 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2263 MODEST_CONF_MSG_SIZE_LIMIT,
2266 g_clear_error (&(priv->error));
2267 max_size = G_MAXINT;
2269 max_size = max_size * KB;
2272 /* Check message size limits. If there is only one message
2273 always retrieve it */
2275 while (!tny_iterator_is_done (iter) && size_ok) {
2276 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2278 if (tny_header_get_message_size (header) >= max_size)
2280 g_object_unref (header);
2283 tny_iterator_next (iter);
2285 g_object_unref (iter);
2289 const gint msg_list_size = compute_message_list_size (header_list);
2291 modest_mail_operation_notify_start (self);
2292 iter = tny_list_create_iterator (header_list);
2293 while (!tny_iterator_is_done (iter)) {
2294 /* notify about the start of the operation */
2295 ModestMailOperationState *state;
2296 state = modest_mail_operation_clone_state (self);
2299 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2302 GetMsgInfo *msg_info = NULL;
2303 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2304 TnyFolder *folder = tny_header_get_folder (header);
2306 /* Create the message info */
2307 msg_info = g_slice_new0 (GetMsgInfo);
2308 msg_info->mail_op = g_object_ref (self);
2309 msg_info->header = g_object_ref (header);
2310 msg_info->user_callback = user_callback;
2311 msg_info->user_data = user_data;
2312 msg_info->destroy_notify = notify;
2313 msg_info->last_total_bytes = 0;
2314 msg_info->sum_total_bytes = 0;
2315 msg_info->total_bytes = msg_list_size;
2317 /* The callback will call it per each header */
2318 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2320 /* Free and go on */
2321 g_object_unref (header);
2322 g_object_unref (folder);
2323 tny_iterator_next (iter);
2325 g_object_unref (iter);
2327 /* Set status failed and set an error */
2328 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2329 /* FIXME: the error msg is different for pop */
2330 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2331 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2332 _("emev_ni_ui_imap_msg_size_exceed_error"));
2333 /* Remove from queue and free resources */
2334 modest_mail_operation_notify_end (self);
2343 modest_mail_operation_remove_msg (ModestMailOperation *self,
2345 gboolean remove_to_trash /*ignored*/)
2348 ModestMailOperationPrivate *priv;
2350 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2351 g_return_if_fail (TNY_IS_HEADER (header));
2353 if (remove_to_trash)
2354 g_warning ("remove to trash is not implemented");
2356 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2357 folder = tny_header_get_folder (header);
2359 /* Get account and set it into mail_operation */
2360 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2361 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2362 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2364 /* remove message from folder */
2365 tny_folder_remove_msg (folder, header, &(priv->error));
2367 gboolean expunge, leave_on_server;
2368 const gchar *account_name;
2369 TnyAccount *account;
2370 ModestTransportStoreProtocol account_proto;
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 account_proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
2386 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2387 modest_tny_folder_is_remote_folder (folder) == FALSE)
2393 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2396 g_object_unref (account);
2402 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2404 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2407 g_object_unref (G_OBJECT (folder));
2409 /* Notify about operation end */
2410 modest_mail_operation_notify_end (self);
2414 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2416 gboolean remove_to_trash /*ignored*/)
2419 ModestMailOperationPrivate *priv;
2420 TnyIterator *iter = NULL;
2421 TnyHeader *header = NULL;
2422 TnyList *remove_headers = NULL;
2423 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2425 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2426 g_return_if_fail (TNY_IS_LIST (headers));
2428 if (remove_to_trash)
2429 g_warning ("remove to trash is not implemented");
2431 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2433 remove_headers = g_object_ref(headers);
2435 /* Get folder from first header and sync it */
2436 iter = tny_list_create_iterator (headers);
2437 header = TNY_HEADER (tny_iterator_get_current (iter));
2438 folder = tny_header_get_folder (header);
2440 /* Don't remove messages that are being sent */
2441 if (modest_tny_folder_is_local_folder (folder)) {
2442 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2444 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2445 TnyTransportAccount *traccount = NULL;
2446 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2447 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2449 ModestTnySendQueueStatus status;
2450 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2451 TnyIterator *iter = tny_list_create_iterator(headers);
2452 g_object_unref(remove_headers);
2453 remove_headers = TNY_LIST(tny_simple_list_new());
2454 while (!tny_iterator_is_done(iter)) {
2456 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2457 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2458 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2459 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2460 tny_list_append(remove_headers, G_OBJECT(hdr));
2462 g_object_unref(hdr);
2464 tny_iterator_next(iter);
2466 g_object_unref(iter);
2467 g_object_unref(traccount);
2471 /* Get account and set it into mail_operation */
2472 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2473 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2474 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2476 /* remove message from folder */
2477 modest_mail_operation_notify_start (self);
2479 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2481 gboolean expunge, leave_on_server;
2482 const gchar *account_name;
2483 TnyAccount *account;
2484 ModestTransportStoreProtocol account_proto;
2486 account = tny_folder_get_account (folder);
2487 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2489 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2492 account_proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
2494 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2495 modest_tny_folder_is_remote_folder (folder) == FALSE)
2501 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2503 g_object_unref (account);
2509 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2511 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2514 g_object_unref (remove_headers);
2515 g_object_unref (header);
2516 g_object_unref (iter);
2517 g_object_unref (G_OBJECT (folder));
2519 /* Notify about operation end */
2520 modest_mail_operation_notify_end (self);
2524 notify_progress_of_multiple_messages (ModestMailOperation *self,
2526 gint *last_total_bytes,
2527 gint *sum_total_bytes,
2529 gboolean increment_done)
2531 ModestMailOperationPrivate *priv;
2532 ModestMailOperationState *state;
2533 gboolean is_num_bytes;
2535 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2537 /* We know that tinymail sends us information about
2538 transferred bytes with this particular message */
2539 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2541 state = modest_mail_operation_clone_state (self);
2542 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2543 /* We know that we're in a different message when the
2544 total number of bytes to transfer is different. Of
2545 course it could fail if we're transferring messages
2546 of the same size, but this is a workarround */
2547 if (status->of_total != *last_total_bytes) {
2548 /* We need to increment the done when there is
2549 no information about each individual
2550 message, we need to do this in message
2551 transfers, and we don't do it for getting
2555 *sum_total_bytes += *last_total_bytes;
2556 *last_total_bytes = status->of_total;
2558 state->bytes_done += status->position + *sum_total_bytes;
2559 state->bytes_total = total_bytes;
2561 /* Notify the status change. Only notify about changes
2562 referred to bytes */
2563 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2567 g_slice_free (ModestMailOperationState, state);
2571 transfer_msgs_status_cb (GObject *obj,
2575 XFerMsgAsyncHelper *helper;
2577 g_return_if_fail (status != NULL);
2578 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2580 helper = (XFerMsgAsyncHelper *) user_data;
2581 g_return_if_fail (helper != NULL);
2583 /* Notify progress */
2584 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2585 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2590 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2592 XFerMsgAsyncHelper *helper;
2593 ModestMailOperation *self;
2594 ModestMailOperationPrivate *priv;
2595 TnyIterator *iter = NULL;
2596 TnyHeader *header = NULL;
2598 helper = (XFerMsgAsyncHelper *) user_data;
2599 self = helper->mail_op;
2601 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2604 priv->error = g_error_copy (err);
2606 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2607 } else if (cancelled) {
2608 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2609 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2610 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2611 _("Error trying to refresh the contents of %s"),
2612 tny_folder_get_name (folder));
2615 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2617 /* Update folder counts */
2618 tny_folder_poke_status (folder);
2619 tny_folder_poke_status (helper->dest_folder);
2623 /* Mark headers as deleted and seen */
2624 if ((helper->delete) &&
2625 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2626 iter = tny_list_create_iterator (helper->headers);
2627 while (!tny_iterator_is_done (iter)) {
2628 header = TNY_HEADER (tny_iterator_get_current (iter));
2629 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2630 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2631 g_object_unref (header);
2633 tny_iterator_next (iter);
2639 /* Notify about operation end */
2640 modest_mail_operation_notify_end (self);
2642 /* If user defined callback function was defined, call it */
2643 if (helper->user_callback) {
2644 /* This is not a GDK lock because we are a Tinymail callback and
2645 * Tinymail already acquires the Gdk lock */
2647 /* no gdk_threads_enter (), CHECKED */
2648 helper->user_callback (self, helper->user_data);
2649 /* no gdk_threads_leave (), CHECKED */
2653 if (helper->headers)
2654 g_object_unref (helper->headers);
2655 if (helper->dest_folder)
2656 g_object_unref (helper->dest_folder);
2657 if (helper->mail_op)
2658 g_object_unref (helper->mail_op);
2660 g_object_unref (folder);
2662 g_object_unref (iter);
2663 g_slice_free (XFerMsgAsyncHelper, helper);
2667 compute_message_list_size (TnyList *headers)
2672 iter = tny_list_create_iterator (headers);
2673 while (!tny_iterator_is_done (iter)) {
2674 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2675 size += tny_header_get_message_size (header);
2676 g_object_unref (header);
2677 tny_iterator_next (iter);
2679 g_object_unref (iter);
2685 compute_message_array_size (GPtrArray *headers)
2690 for (i = 0; i < headers->len; i++) {
2691 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2692 size += tny_header_get_message_size (header);
2700 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2703 gboolean delete_original,
2704 XferAsyncUserCallback user_callback,
2707 ModestMailOperationPrivate *priv = NULL;
2708 TnyIterator *iter = NULL;
2709 TnyFolder *src_folder = NULL;
2710 XFerMsgAsyncHelper *helper = NULL;
2711 TnyHeader *header = NULL;
2712 ModestTnyFolderRules rules = 0;
2714 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2715 g_return_if_fail (headers && TNY_IS_LIST (headers));
2716 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2718 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2719 priv->total = tny_list_get_length (headers);
2721 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2722 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2724 /* Apply folder rules */
2725 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2726 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2727 /* Set status failed and set an error */
2728 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2729 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2730 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2731 _CS("ckct_ib_unable_to_paste_here"));
2732 /* Notify the queue */
2733 modest_mail_operation_notify_end (self);
2737 /* Get source folder */
2738 iter = tny_list_create_iterator (headers);
2739 header = TNY_HEADER (tny_iterator_get_current (iter));
2741 src_folder = tny_header_get_folder (header);
2742 g_object_unref (header);
2744 g_object_unref (iter);
2746 if (src_folder == NULL) {
2747 /* Notify the queue */
2748 modest_mail_operation_notify_end (self);
2750 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2755 /* Check folder source and destination */
2756 if (src_folder == folder) {
2757 /* Set status failed and set an error */
2758 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2759 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2760 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2761 _("mail_in_ui_folder_copy_target_error"));
2763 /* Notify the queue */
2764 modest_mail_operation_notify_end (self);
2767 g_object_unref (src_folder);
2771 /* Create the helper */
2772 helper = g_slice_new0 (XFerMsgAsyncHelper);
2773 helper->mail_op = g_object_ref(self);
2774 helper->dest_folder = g_object_ref(folder);
2775 helper->headers = g_object_ref(headers);
2776 helper->user_callback = user_callback;
2777 helper->user_data = user_data;
2778 helper->delete = delete_original;
2779 helper->last_total_bytes = 0;
2780 helper->sum_total_bytes = 0;
2781 helper->total_bytes = compute_message_list_size (headers);
2783 /* Get account and set it into mail_operation */
2784 priv->account = modest_tny_folder_get_account (src_folder);
2786 /* Transfer messages */
2787 modest_mail_operation_notify_start (self);
2788 tny_folder_transfer_msgs_async (src_folder,
2793 transfer_msgs_status_cb,
2799 on_refresh_folder (TnyFolder *folder,
2804 RefreshAsyncHelper *helper = NULL;
2805 ModestMailOperation *self = NULL;
2806 ModestMailOperationPrivate *priv = NULL;
2808 helper = (RefreshAsyncHelper *) user_data;
2809 self = helper->mail_op;
2810 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2812 g_return_if_fail(priv!=NULL);
2815 priv->error = g_error_copy (error);
2816 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2821 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2822 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2823 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2824 _("Error trying to refresh the contents of %s"),
2825 tny_folder_get_name (folder));
2829 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2832 /* Call user defined callback, if it exists */
2833 if (helper->user_callback) {
2835 /* This is not a GDK lock because we are a Tinymail callback and
2836 * Tinymail already acquires the Gdk lock */
2837 helper->user_callback (self, folder, helper->user_data);
2841 g_slice_free (RefreshAsyncHelper, helper);
2843 /* Notify about operation end */
2844 modest_mail_operation_notify_end (self);
2845 g_object_unref(self);
2849 on_refresh_folder_status_update (GObject *obj,
2853 RefreshAsyncHelper *helper = NULL;
2854 ModestMailOperation *self = NULL;
2855 ModestMailOperationPrivate *priv = NULL;
2856 ModestMailOperationState *state;
2858 g_return_if_fail (user_data != NULL);
2859 g_return_if_fail (status != NULL);
2860 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2862 helper = (RefreshAsyncHelper *) user_data;
2863 self = helper->mail_op;
2864 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2866 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2868 priv->done = status->position;
2869 priv->total = status->of_total;
2871 state = modest_mail_operation_clone_state (self);
2873 /* This is not a GDK lock because we are a Tinymail callback and
2874 * Tinymail already acquires the Gdk lock */
2875 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2877 g_slice_free (ModestMailOperationState, state);
2881 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2883 RefreshAsyncUserCallback user_callback,
2886 ModestMailOperationPrivate *priv = NULL;
2887 RefreshAsyncHelper *helper = NULL;
2889 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2891 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2893 /* Get account and set it into mail_operation */
2894 priv->account = modest_tny_folder_get_account (folder);
2895 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2897 /* Create the helper */
2898 helper = g_slice_new0 (RefreshAsyncHelper);
2899 helper->mail_op = g_object_ref(self);
2900 helper->user_callback = user_callback;
2901 helper->user_data = user_data;
2903 /* Refresh the folder. TODO: tinymail could issue a status
2904 updates before the callback call then this could happen. We
2905 must review the design */
2906 modest_mail_operation_notify_start (self);
2908 /* notify that the operation was started */
2909 ModestMailOperationState *state;
2910 state = modest_mail_operation_clone_state (self);
2913 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2916 tny_folder_refresh_async (folder,
2918 on_refresh_folder_status_update,
2924 modest_mail_operation_notify_start (ModestMailOperation *self)
2926 ModestMailOperationPrivate *priv = NULL;
2928 g_return_if_fail (self);
2930 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2932 /* Ensure that all the fields are filled correctly */
2933 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
2935 /* Notify the observers about the mail operation. We do not
2936 wrapp this emission because we assume that this function is
2937 always called from within the main lock */
2938 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
2943 * It's used by the mail operation queue to notify the observers
2944 * attached to that signal that the operation finished. We need to use
2945 * that because tinymail does not give us the progress of a given
2946 * operation when it finishes (it directly calls the operation
2950 modest_mail_operation_notify_end (ModestMailOperation *self)
2952 ModestMailOperationPrivate *priv = NULL;
2954 g_return_if_fail (self);
2956 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2958 /* Notify the observers about the mail operation end. We do
2959 not wrapp this emission because we assume that this
2960 function is always called from within the main lock */
2961 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
2963 /* Remove the error user data */
2964 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
2965 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
2969 modest_mail_operation_get_account (ModestMailOperation *self)
2971 ModestMailOperationPrivate *priv = NULL;
2973 g_return_val_if_fail (self, NULL);
2975 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2977 return (priv->account) ? g_object_ref (priv->account) : NULL;
2981 modest_mail_operation_noop (ModestMailOperation *self)
2983 ModestMailOperationPrivate *priv = NULL;
2985 g_return_if_fail (self);
2987 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2988 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2989 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2993 /* This mail operation does nothing actually */
2994 modest_mail_operation_notify_start (self);
2995 modest_mail_operation_notify_end (self);