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"
60 #include <modest-count-stream.h>
61 #include <libgnomevfs/gnome-vfs.h>
62 #include "modest-utils.h"
67 * Remove all these #ifdef stuff when the tinymail's idle calls become
70 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
72 /* 'private'/'protected' functions */
73 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
74 static void modest_mail_operation_init (ModestMailOperation *obj);
75 static void modest_mail_operation_finalize (GObject *obj);
77 static void get_msg_async_cb (TnyFolder *folder,
83 static void get_msg_status_cb (GObject *obj,
87 static void modest_mail_operation_notify_start (ModestMailOperation *self);
88 static void modest_mail_operation_notify_end (ModestMailOperation *self);
90 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
92 gint *last_total_bytes,
93 gint *sum_total_bytes,
95 gboolean increment_done);
97 static guint compute_message_list_size (TnyList *headers);
99 static guint compute_message_array_size (GPtrArray *headers);
101 static int compare_headers_by_date (gconstpointer a,
104 enum _ModestMailOperationSignals
106 PROGRESS_CHANGED_SIGNAL,
107 OPERATION_STARTED_SIGNAL,
108 OPERATION_FINISHED_SIGNAL,
112 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
113 struct _ModestMailOperationPrivate {
119 ErrorCheckingUserCallback error_checking;
120 gpointer error_checking_user_data;
121 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
122 ModestMailOperationStatus status;
123 ModestMailOperationTypeOperation op_type;
126 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
127 MODEST_TYPE_MAIL_OPERATION, \
128 ModestMailOperationPrivate))
130 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
131 priv->status = new_status;\
136 GetMsgAsyncUserCallback user_callback;
139 ModestMailOperation *mail_op;
140 GDestroyNotify destroy_notify;
141 gint last_total_bytes;
142 gint sum_total_bytes;
147 ModestMailOperation *mail_op;
149 gulong msg_sent_handler;
150 gulong error_happened_handler;
153 static void send_mail_msg_sent_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
154 guint nth, guint total, gpointer userdata);
155 static void send_mail_error_happened_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
156 GError *error, gpointer userdata);
157 static void common_send_mail_operation_end (TnySendQueue *queue, TnyMsg *msg,
160 typedef struct _RefreshAsyncHelper {
161 ModestMailOperation *mail_op;
162 RefreshAsyncUserCallback user_callback;
164 } RefreshAsyncHelper;
166 typedef struct _XFerMsgsAsyncHelper
168 ModestMailOperation *mail_op;
170 TnyFolder *dest_folder;
171 XferMsgsAsyncUserCallback user_callback;
174 gint last_total_bytes;
175 gint sum_total_bytes;
177 } XFerMsgsAsyncHelper;
179 typedef struct _XFerFolderAsyncHelper
181 ModestMailOperation *mail_op;
182 XferFolderAsyncUserCallback user_callback;
184 } XFerFolderAsyncHelper;
186 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
190 static void modest_mail_operation_create_msg (ModestMailOperation *self,
191 const gchar *from, const gchar *to,
192 const gchar *cc, const gchar *bcc,
193 const gchar *subject, const gchar *plain_body,
194 const gchar *html_body, const GList *attachments_list,
195 const GList *images_list,
196 TnyHeaderFlags priority_flags,
197 ModestMailOperationCreateMsgCallback callback,
200 static gboolean idle_notify_queue (gpointer data);
203 ModestMailOperation *mail_op;
211 GList *attachments_list;
213 TnyHeaderFlags priority_flags;
214 ModestMailOperationCreateMsgCallback callback;
220 ModestMailOperation *mail_op;
222 ModestMailOperationCreateMsgCallback callback;
227 static GObjectClass *parent_class = NULL;
229 static guint signals[NUM_SIGNALS] = {0};
232 modest_mail_operation_get_type (void)
234 static GType my_type = 0;
236 static const GTypeInfo my_info = {
237 sizeof(ModestMailOperationClass),
238 NULL, /* base init */
239 NULL, /* base finalize */
240 (GClassInitFunc) modest_mail_operation_class_init,
241 NULL, /* class finalize */
242 NULL, /* class data */
243 sizeof(ModestMailOperation),
245 (GInstanceInitFunc) modest_mail_operation_init,
248 my_type = g_type_register_static (G_TYPE_OBJECT,
249 "ModestMailOperation",
256 modest_mail_operation_class_init (ModestMailOperationClass *klass)
258 GObjectClass *gobject_class;
259 gobject_class = (GObjectClass*) klass;
261 parent_class = g_type_class_peek_parent (klass);
262 gobject_class->finalize = modest_mail_operation_finalize;
264 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
267 * ModestMailOperation::progress-changed
268 * @self: the #MailOperation that emits the signal
269 * @user_data: user data set when the signal handler was connected
271 * Emitted when the progress of a mail operation changes
273 signals[PROGRESS_CHANGED_SIGNAL] =
274 g_signal_new ("progress-changed",
275 G_TYPE_FROM_CLASS (gobject_class),
277 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
279 g_cclosure_marshal_VOID__POINTER,
280 G_TYPE_NONE, 1, G_TYPE_POINTER);
284 * This signal is issued whenever a mail operation starts, and
285 * starts mean when the tinymail operation is issued. This
286 * means that it could happen that something wrong happens and
287 * the tinymail function is never called. In this situation a
288 * operation-finished will be issued without any
291 signals[OPERATION_STARTED_SIGNAL] =
292 g_signal_new ("operation-started",
293 G_TYPE_FROM_CLASS (gobject_class),
295 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
297 g_cclosure_marshal_VOID__VOID,
302 * This signal is issued whenever a mail operation
303 * finishes. Note that this signal could be issued without any
304 * previous "operation-started" signal, because this last one
305 * is only issued when the tinymail operation is successfully
308 signals[OPERATION_FINISHED_SIGNAL] =
309 g_signal_new ("operation-finished",
310 G_TYPE_FROM_CLASS (gobject_class),
312 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
314 g_cclosure_marshal_VOID__VOID,
319 modest_mail_operation_init (ModestMailOperation *obj)
321 ModestMailOperationPrivate *priv;
323 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
325 priv->account = NULL;
326 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
327 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
332 priv->error_checking = NULL;
333 priv->error_checking_user_data = NULL;
337 modest_mail_operation_finalize (GObject *obj)
339 ModestMailOperationPrivate *priv;
341 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
346 g_error_free (priv->error);
350 g_object_unref (priv->source);
354 g_object_unref (priv->account);
355 priv->account = NULL;
359 G_OBJECT_CLASS(parent_class)->finalize (obj);
363 modest_mail_operation_new (GObject *source)
365 ModestMailOperation *obj;
366 ModestMailOperationPrivate *priv;
368 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
369 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
372 priv->source = g_object_ref(source);
378 modest_mail_operation_new_with_error_handling (GObject *source,
379 ErrorCheckingUserCallback error_handler,
381 ErrorCheckingUserDataDestroyer error_handler_destroyer)
383 ModestMailOperation *obj;
384 ModestMailOperationPrivate *priv;
386 obj = modest_mail_operation_new (source);
387 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
389 g_return_val_if_fail (error_handler != NULL, obj);
390 priv->error_checking = error_handler;
391 priv->error_checking_user_data = user_data;
392 priv->error_checking_user_data_destroyer = error_handler_destroyer;
398 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
400 ModestMailOperationPrivate *priv;
402 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
404 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
405 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
407 /* Call the user callback */
408 if (priv->error_checking != NULL)
409 priv->error_checking (self, priv->error_checking_user_data);
413 ModestMailOperationTypeOperation
414 modest_mail_operation_get_type_operation (ModestMailOperation *self)
416 ModestMailOperationPrivate *priv;
418 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
419 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
421 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
423 return priv->op_type;
427 modest_mail_operation_is_mine (ModestMailOperation *self,
430 ModestMailOperationPrivate *priv;
432 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
435 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
436 if (priv->source == NULL) return FALSE;
438 return priv->source == me;
442 modest_mail_operation_get_source (ModestMailOperation *self)
444 ModestMailOperationPrivate *priv;
446 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
449 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
451 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
455 return (priv->source) ? g_object_ref (priv->source) : NULL;
458 ModestMailOperationStatus
459 modest_mail_operation_get_status (ModestMailOperation *self)
461 ModestMailOperationPrivate *priv;
463 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
464 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
465 MODEST_MAIL_OPERATION_STATUS_INVALID);
467 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
469 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
470 return MODEST_MAIL_OPERATION_STATUS_INVALID;
477 modest_mail_operation_get_error (ModestMailOperation *self)
479 ModestMailOperationPrivate *priv;
481 g_return_val_if_fail (self, NULL);
482 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
484 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
487 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
495 modest_mail_operation_cancel (ModestMailOperation *self)
497 ModestMailOperationPrivate *priv;
498 gboolean canceled = FALSE;
500 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
502 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
504 /* Note that if we call cancel with an already canceled mail
505 operation the progress changed signal won't be emitted */
506 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
510 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
512 /* Cancel the mail operation */
513 g_return_val_if_fail (priv->account, FALSE);
514 tny_account_cancel (priv->account);
516 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
517 ModestTnySendQueue *queue;
518 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account));
520 /* Cancel the sending of the following next messages */
521 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
528 modest_mail_operation_get_task_done (ModestMailOperation *self)
530 ModestMailOperationPrivate *priv;
532 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
535 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
540 modest_mail_operation_get_task_total (ModestMailOperation *self)
542 ModestMailOperationPrivate *priv;
544 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
547 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
552 modest_mail_operation_is_finished (ModestMailOperation *self)
554 ModestMailOperationPrivate *priv;
555 gboolean retval = FALSE;
557 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
560 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
562 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
563 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
564 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
565 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
575 * Creates an image of the current state of a mail operation, the
576 * caller must free it
578 static ModestMailOperationState *
579 modest_mail_operation_clone_state (ModestMailOperation *self)
581 ModestMailOperationState *state;
582 ModestMailOperationPrivate *priv;
584 /* FIXME: this should be fixed properly
586 * in some cases, priv was NULL, so checking here to
589 g_return_val_if_fail (self, NULL);
590 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
591 g_return_val_if_fail (priv, NULL);
596 state = g_slice_new (ModestMailOperationState);
598 state->status = priv->status;
599 state->op_type = priv->op_type;
600 state->done = priv->done;
601 state->total = priv->total;
602 state->finished = modest_mail_operation_is_finished (self);
603 state->bytes_done = 0;
604 state->bytes_total = 0;
609 /* ******************************************************************* */
610 /* ************************** SEND ACTIONS ************************* */
611 /* ******************************************************************* */
614 modest_mail_operation_send_mail (ModestMailOperation *self,
615 TnyTransportAccount *transport_account,
618 TnySendQueue *send_queue = NULL;
619 ModestMailOperationPrivate *priv;
622 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
623 g_return_if_fail (transport_account && TNY_IS_TRANSPORT_ACCOUNT (transport_account));
624 g_return_if_fail (msg && TNY_IS_MSG (msg));
626 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
628 /* Get account and set it into mail_operation */
629 priv->account = g_object_ref (transport_account);
630 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
634 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
635 if (!TNY_IS_SEND_QUEUE(send_queue)) {
636 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
637 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
638 "modest: could not find send queue for account\n");
639 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
640 modest_mail_operation_notify_end (self);
643 /* Add the msg to the queue */
644 modest_mail_operation_notify_start (self);
646 info = g_slice_new0 (SendMsgInfo);
648 info->mail_op = g_object_ref (self);
649 info->msg = g_object_ref (msg);
650 info->msg_sent_handler = g_signal_connect (G_OBJECT (send_queue), "msg-sent",
651 G_CALLBACK (send_mail_msg_sent_handler), info);
652 info->error_happened_handler = g_signal_connect (G_OBJECT (send_queue), "error-happened",
653 G_CALLBACK (send_mail_error_happened_handler), info);
655 tny_send_queue_add_async (send_queue, msg, NULL, NULL, NULL);
657 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
663 common_send_mail_operation_end (TnySendQueue *queue, TnyMsg *msg,
666 g_signal_handler_disconnect (queue, info->msg_sent_handler);
667 g_signal_handler_disconnect (queue, info->error_happened_handler);
669 g_object_unref (info->msg);
670 modest_mail_operation_notify_end (info->mail_op);
671 g_object_unref (info->mail_op);
673 g_slice_free (SendMsgInfo, info);
677 send_mail_msg_sent_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
678 guint nth, guint total, gpointer userdata)
680 SendMsgInfo *info = (SendMsgInfo *) userdata;
681 TnyHeader *hdr1, *hdr2;
682 const char *msgid1, *msgid2;
683 hdr1 = tny_msg_get_header(msg);
684 hdr2 = tny_msg_get_header(info->msg);
685 msgid1 = tny_header_get_message_id(hdr1);
686 msgid2 = tny_header_get_message_id(hdr2);
687 if (msgid1 == NULL) msgid1 = "(null)";
688 if (msgid2 == NULL) msgid2 = "(null)";
690 if (!strcmp (msgid1, msgid2)) {
691 ModestMailOperationPrivate *priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
692 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
694 common_send_mail_operation_end (queue, msg, info);
696 g_object_unref(G_OBJECT(hdr1));
697 g_object_unref(G_OBJECT(hdr2));
701 send_mail_error_happened_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
702 GError *error, gpointer userdata)
704 SendMsgInfo *info = (SendMsgInfo *) userdata;
705 TnyHeader *hdr1, *hdr2;
706 const char *msgid1, *msgid2;
708 if (!TNY_IS_MSG(msg)) {
709 g_warning ("%s: did not receive a valid msg", __FUNCTION__);
713 hdr1 = tny_msg_get_header(msg);
714 hdr2 = tny_msg_get_header(info->msg);
715 msgid1 = tny_header_get_message_id(hdr1);
716 msgid2 = tny_header_get_message_id(hdr2);
717 if (msgid1 == NULL) msgid1 = "(null)";
718 if (msgid2 == NULL) msgid2 = "(null)";
720 if (!strcmp (msgid1, msgid2)) {
721 ModestMailOperationPrivate *priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
722 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
723 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
724 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
725 "modest: send mail failed\n");
727 common_send_mail_operation_end (queue, msg, info);
729 g_object_unref(G_OBJECT(hdr1));
730 g_object_unref(G_OBJECT(hdr2));
735 idle_create_msg_cb (gpointer idle_data)
737 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
739 /* This is a GDK lock because we are an idle callback and
740 * info->callback can contain Gtk+ code */
742 gdk_threads_enter (); /* CHECKED */
743 info->callback (info->mail_op, info->msg, info->userdata);
745 g_object_unref (info->mail_op);
747 g_object_unref (info->msg);
748 g_slice_free (CreateMsgIdleInfo, info);
749 gdk_threads_leave (); /* CHECKED */
755 create_msg_thread (gpointer thread_data)
757 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
758 TnyMsg *new_msg = NULL;
759 ModestMailOperationPrivate *priv;
761 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
762 if (info->html_body == NULL) {
763 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
764 info->bcc, info->subject, info->plain_body,
765 info->attachments_list);
767 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
768 info->bcc, info->subject, info->html_body,
769 info->plain_body, info->attachments_list,
776 /* Set priority flags in message */
777 header = tny_msg_get_header (new_msg);
778 tny_header_set_flag (header, info->priority_flags);
780 /* Set attachment flags in message */
781 if (info->attachments_list != NULL)
782 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
784 g_object_unref (G_OBJECT(header));
786 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
787 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
788 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
789 "modest: failed to create a new msg\n");
797 g_free (info->plain_body);
798 g_free (info->html_body);
799 g_free (info->subject);
800 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
801 g_list_free (info->attachments_list);
802 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
803 g_list_free (info->images_list);
805 if (info->callback) {
806 CreateMsgIdleInfo *idle_info;
807 idle_info = g_slice_new0 (CreateMsgIdleInfo);
808 idle_info->mail_op = g_object_ref (info->mail_op);
809 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
810 idle_info->callback = info->callback;
811 idle_info->userdata = info->userdata;
812 g_idle_add (idle_create_msg_cb, idle_info);
814 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
817 g_object_unref (info->mail_op);
818 g_slice_free (CreateMsgInfo, info);
819 if (new_msg) g_object_unref(new_msg);
825 modest_mail_operation_create_msg (ModestMailOperation *self,
826 const gchar *from, const gchar *to,
827 const gchar *cc, const gchar *bcc,
828 const gchar *subject, const gchar *plain_body,
829 const gchar *html_body,
830 const GList *attachments_list,
831 const GList *images_list,
832 TnyHeaderFlags priority_flags,
833 ModestMailOperationCreateMsgCallback callback,
836 ModestMailOperationPrivate *priv;
837 CreateMsgInfo *info = NULL;
839 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
841 info = g_slice_new0 (CreateMsgInfo);
842 info->mail_op = g_object_ref (self);
844 info->from = g_strdup (from);
845 info->to = g_strdup (to);
846 info->cc = g_strdup (cc);
847 info->bcc = g_strdup (bcc);
848 info->subject = g_strdup (subject);
849 info->plain_body = g_strdup (plain_body);
850 info->html_body = g_strdup (html_body);
851 info->attachments_list = g_list_copy ((GList *) attachments_list);
852 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
853 info->images_list = g_list_copy ((GList *) images_list);
854 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
855 info->priority_flags = priority_flags;
857 info->callback = callback;
858 info->userdata = userdata;
860 g_thread_create (create_msg_thread, info, FALSE, NULL);
865 TnyTransportAccount *transport_account;
870 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
874 ModestMailOperationPrivate *priv = NULL;
875 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
876 TnyFolder *draft_folder = NULL;
877 TnyFolder *outbox_folder = NULL;
878 TnyHeader *header = NULL;
885 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
888 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
889 modest_mail_operation_notify_end (self);
893 /* Call mail operation */
894 modest_mail_operation_send_mail (self, info->transport_account, msg);
896 if (info->draft_msg != NULL) {
897 TnyFolder *folder = NULL;
898 TnyFolder *src_folder = NULL;
899 TnyFolderType folder_type;
900 TnyTransportAccount *transport_account = NULL;
902 /* To remove the old mail from its source folder, we need to get the
903 * transport account of the original draft message (the transport account
904 * might have been changed by the user) */
905 header = tny_msg_get_header (info->draft_msg);
906 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
907 modest_runtime_get_account_store(), header);
908 if (transport_account == NULL)
909 transport_account = g_object_ref(info->transport_account);
910 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
911 TNY_FOLDER_TYPE_DRAFTS);
912 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
913 TNY_FOLDER_TYPE_OUTBOX);
914 g_object_unref(transport_account);
917 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
921 if (!outbox_folder) {
922 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
927 folder = tny_msg_get_folder (info->draft_msg);
928 if (folder == NULL) goto end;
929 folder_type = modest_tny_folder_guess_folder_type (folder);
931 if (folder_type == TNY_FOLDER_TYPE_INVALID)
932 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
934 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
935 src_folder = outbox_folder;
937 src_folder = draft_folder;
939 /* Note: This can fail (with a warning) if the message is not really already in a folder,
940 * because this function requires it to have a UID. */
941 tny_folder_remove_msg (src_folder, header, NULL);
943 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
944 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
946 g_object_unref (folder);
951 g_object_unref (header);
955 g_object_unref (info->draft_msg);
957 g_object_unref (draft_folder);
959 g_object_unref (outbox_folder);
960 if (info->transport_account)
961 g_object_unref (info->transport_account);
962 g_slice_free (SendNewMailInfo, info);
966 modest_mail_operation_send_new_mail (ModestMailOperation *self,
967 TnyTransportAccount *transport_account,
969 const gchar *from, const gchar *to,
970 const gchar *cc, const gchar *bcc,
971 const gchar *subject, const gchar *plain_body,
972 const gchar *html_body,
973 const GList *attachments_list,
974 const GList *images_list,
975 TnyHeaderFlags priority_flags)
977 ModestMailOperationPrivate *priv = NULL;
978 SendNewMailInfo *info;
980 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
981 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
983 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
984 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
985 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
986 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
988 /* Check parametters */
990 /* Set status failed and set an error */
991 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
992 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
993 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
994 _("Error trying to send a mail. You need to set at least one recipient"));
997 info = g_slice_new0 (SendNewMailInfo);
998 info->transport_account = transport_account;
999 if (transport_account)
1000 g_object_ref (transport_account);
1001 info->draft_msg = draft_msg;
1003 g_object_ref (draft_msg);
1006 modest_mail_operation_notify_start (self);
1007 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1008 attachments_list, images_list, priority_flags,
1009 modest_mail_operation_send_new_mail_cb, info);
1015 TnyTransportAccount *transport_account;
1017 SaveToDraftstCallback callback;
1021 ModestMailOperation *mailop;
1022 } SaveToDraftsAddMsgInfo;
1025 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1030 ModestMailOperationPrivate *priv = NULL;
1031 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1033 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1036 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1037 g_error_free(priv->error);
1040 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1042 if ((!priv->error) && (info->draft_msg != NULL)) {
1043 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1044 TnyFolder *src_folder = tny_header_get_folder (header);
1046 /* Remove the old draft */
1047 tny_folder_remove_msg (src_folder, header, NULL);
1049 /* Synchronize to expunge and to update the msg counts */
1050 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1051 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1053 g_object_unref (G_OBJECT(header));
1054 g_object_unref (G_OBJECT(src_folder));
1058 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1060 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1062 /* Call the user callback */
1064 info->callback (info->mailop, info->msg, info->user_data);
1066 if (info->transport_account)
1067 g_object_unref (G_OBJECT(info->transport_account));
1068 if (info->draft_msg)
1069 g_object_unref (G_OBJECT (info->draft_msg));
1071 g_object_unref (G_OBJECT(info->drafts));
1073 g_object_unref (G_OBJECT (info->msg));
1075 modest_mail_operation_notify_end (info->mailop);
1076 g_object_unref(info->mailop);
1077 g_slice_free (SaveToDraftsAddMsgInfo, info);
1082 TnyTransportAccount *transport_account;
1084 SaveToDraftstCallback callback;
1089 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1093 TnyFolder *drafts = NULL;
1094 ModestMailOperationPrivate *priv = NULL;
1095 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1097 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1100 if (!(priv->error)) {
1101 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1102 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1103 "modest: failed to create a new msg\n");
1106 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1107 TNY_FOLDER_TYPE_DRAFTS);
1108 if (!drafts && !(priv->error)) {
1109 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1110 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1111 "modest: failed to create a new msg\n");
1116 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1117 cb_info->transport_account = g_object_ref(info->transport_account);
1118 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1119 cb_info->callback = info->callback;
1120 cb_info->user_data = info->user_data;
1121 cb_info->drafts = g_object_ref(drafts);
1122 cb_info->msg = g_object_ref(msg);
1123 cb_info->mailop = g_object_ref(self);
1124 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1127 /* Call the user callback */
1128 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1130 info->callback (self, msg, info->user_data);
1131 modest_mail_operation_notify_end (self);
1135 g_object_unref (G_OBJECT(drafts));
1136 if (info->draft_msg)
1137 g_object_unref (G_OBJECT (info->draft_msg));
1138 if (info->transport_account)
1139 g_object_unref (G_OBJECT(info->transport_account));
1140 g_slice_free (SaveToDraftsInfo, info);
1144 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1145 TnyTransportAccount *transport_account,
1147 const gchar *from, const gchar *to,
1148 const gchar *cc, const gchar *bcc,
1149 const gchar *subject, const gchar *plain_body,
1150 const gchar *html_body,
1151 const GList *attachments_list,
1152 const GList *images_list,
1153 TnyHeaderFlags priority_flags,
1154 SaveToDraftstCallback callback,
1157 ModestMailOperationPrivate *priv = NULL;
1158 SaveToDraftsInfo *info = NULL;
1160 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1161 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1163 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1165 /* Get account and set it into mail_operation */
1166 priv->account = g_object_ref (transport_account);
1167 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1169 info = g_slice_new0 (SaveToDraftsInfo);
1170 info->transport_account = g_object_ref (transport_account);
1171 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1172 info->callback = callback;
1173 info->user_data = user_data;
1175 modest_mail_operation_notify_start (self);
1176 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1177 attachments_list, images_list, priority_flags,
1178 modest_mail_operation_save_to_drafts_cb, info);
1183 ModestMailOperation *mail_op;
1184 TnyMimePart *mime_part;
1186 GetMimePartSizeCallback callback;
1188 } GetMimePartSizeInfo;
1190 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1191 /* We use this folder observer to track the headers that have been
1192 * added to a folder */
1195 TnyList *new_headers;
1196 } InternalFolderObserver;
1199 GObjectClass parent;
1200 } InternalFolderObserverClass;
1202 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1204 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1205 internal_folder_observer,
1207 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1211 foreach_add_item (gpointer header, gpointer user_data)
1213 tny_list_prepend (TNY_LIST (user_data),
1214 g_object_ref (G_OBJECT (header)));
1217 /* This is the method that looks for new messages in a folder */
1219 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1221 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1223 TnyFolderChangeChanged changed;
1225 changed = tny_folder_change_get_changed (change);
1227 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1230 /* Get added headers */
1231 list = tny_simple_list_new ();
1232 tny_folder_change_get_added_headers (change, list);
1234 /* Add them to the folder observer */
1235 tny_list_foreach (list, foreach_add_item,
1236 derived->new_headers);
1238 g_object_unref (G_OBJECT (list));
1243 internal_folder_observer_init (InternalFolderObserver *self)
1245 self->new_headers = tny_simple_list_new ();
1248 internal_folder_observer_finalize (GObject *object)
1250 InternalFolderObserver *self;
1252 self = (InternalFolderObserver *) object;
1253 g_object_unref (self->new_headers);
1255 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1258 tny_folder_observer_init (TnyFolderObserverIface *iface)
1260 iface->update_func = internal_folder_observer_update;
1263 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1265 GObjectClass *object_class;
1267 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1268 object_class = (GObjectClass*) klass;
1269 object_class->finalize = internal_folder_observer_finalize;
1274 ModestMailOperation *mail_op;
1275 gchar *account_name;
1276 UpdateAccountCallback callback;
1281 TnyFolderObserver *inbox_observer;
1282 RetrieveAllCallback retrieve_all_cb;
1283 } UpdateAccountInfo;
1287 destroy_update_account_info (UpdateAccountInfo *info)
1289 g_free (info->account_name);
1290 g_object_unref (info->folders);
1291 g_object_unref (info->mail_op);
1292 g_slice_free (UpdateAccountInfo, info);
1296 update_account_get_msg_async_cb (TnyFolder *folder,
1302 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1304 /* Just delete the helper. Don't do anything with the new
1305 msg. There is also no need to check for errors */
1306 g_object_unref (msg_info->mail_op);
1307 g_object_unref (msg_info->header);
1308 g_slice_free (GetMsgInfo, msg_info);
1312 guint error_handler;
1314 ModestMailOperation *mail_op;
1315 } UpdateAccountSendQueueFlushInfo;
1318 update_account_finalize (TnySendQueue *queue,
1319 UpdateAccountSendQueueFlushInfo *info)
1321 ModestMailOperationPrivate *priv;
1323 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1326 /* The last one finish the mail operation */
1327 if (priv->done == priv->total) {
1329 modest_mail_operation_notify_end (info->mail_op);
1332 g_object_unref (info->mail_op);
1333 g_signal_handler_disconnect (queue, info->error_handler);
1334 g_signal_handler_disconnect (queue, info->sent_handler);
1335 g_slice_free (UpdateAccountSendQueueFlushInfo, info);
1340 update_account_on_msg_sent_cb (TnySendQueue *queue,
1347 UpdateAccountSendQueueFlushInfo *info;
1348 info = (UpdateAccountSendQueueFlushInfo *) user_data;
1350 update_account_finalize (queue, info);
1354 update_account_on_error_happened_cb (TnySendQueue *queue,
1360 UpdateAccountSendQueueFlushInfo *info;
1361 info = (UpdateAccountSendQueueFlushInfo *) user_data;
1363 update_account_finalize (queue, info);
1368 inbox_refreshed_cb (TnyFolder *inbox,
1373 UpdateAccountInfo *info;
1374 ModestMailOperationPrivate *priv;
1375 TnyIterator *new_headers_iter;
1376 GPtrArray *new_headers_array = NULL;
1377 gint max_size, retrieve_limit, i;
1378 ModestAccountMgr *mgr;
1379 ModestAccountRetrieveType retrieve_type;
1380 TnyList *new_headers = NULL;
1381 gboolean headers_only, ignore_limit;
1382 TnyTransportAccount *transport_account;
1383 gboolean end_operation;
1385 info = (UpdateAccountInfo *) user_data;
1386 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1387 mgr = modest_runtime_get_account_mgr ();
1389 if (canceled || err || !inbox) {
1390 /* Try to send anyway */
1394 /* Get the message max size */
1395 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1396 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1398 max_size = G_MAXINT;
1400 max_size = max_size * KB;
1402 /* Create the new headers array. We need it to sort the
1403 new headers by date */
1404 new_headers_array = g_ptr_array_new ();
1405 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1406 while (!tny_iterator_is_done (new_headers_iter)) {
1407 TnyHeader *header = NULL;
1409 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1410 /* Apply per-message size limits */
1411 if (tny_header_get_message_size (header) < max_size)
1412 g_ptr_array_add (new_headers_array, g_object_ref (header));
1414 g_object_unref (header);
1415 tny_iterator_next (new_headers_iter);
1417 g_object_unref (new_headers_iter);
1418 tny_folder_remove_observer (inbox, info->inbox_observer);
1419 g_object_unref (info->inbox_observer);
1420 info->inbox_observer = NULL;
1422 /* Update the last updated key, even if we don't have to get new headers */
1423 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1425 if (new_headers_array->len == 0)
1428 /* Get per-account message amount retrieval limit */
1429 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1430 if (retrieve_limit == 0)
1431 retrieve_limit = G_MAXINT;
1433 /* Get per-account retrieval type */
1434 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1435 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1438 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1440 /* Ask the users if they want to retrieve all the messages
1441 even though the limit was exceeded */
1442 ignore_limit = FALSE;
1443 if (new_headers_array->len > retrieve_limit) {
1444 /* Ask the user if a callback has been specified and
1445 if the mail operation has a source (this means that
1446 was invoked by the user and not automatically by a
1448 if (info->retrieve_all_cb && priv->source)
1449 ignore_limit = info->retrieve_all_cb (priv->source,
1450 new_headers_array->len,
1454 if (!headers_only) {
1456 const gint msg_list_size = compute_message_array_size (new_headers_array);
1460 priv->total = new_headers_array->len;
1462 priv->total = MIN (new_headers_array->len, retrieve_limit);
1463 while (msg_num < priv->total) {
1464 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1465 TnyFolder *folder = tny_header_get_folder (header);
1466 GetMsgInfo *msg_info;
1468 /* Create the message info */
1469 msg_info = g_slice_new0 (GetMsgInfo);
1470 msg_info->mail_op = g_object_ref (info->mail_op);
1471 msg_info->header = g_object_ref (header);
1472 msg_info->total_bytes = msg_list_size;
1474 /* Get message in an async way */
1475 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1476 get_msg_status_cb, msg_info);
1478 g_object_unref (folder);
1484 /* Copy the headers to a list and free the array */
1485 new_headers = tny_simple_list_new ();
1486 for (i=0; i < new_headers_array->len; i++) {
1487 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1488 tny_list_append (new_headers, G_OBJECT (header));
1490 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1491 g_ptr_array_free (new_headers_array, FALSE);
1494 /* Get the transport account */
1495 transport_account = (TnyTransportAccount *)
1496 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1497 info->account_name);
1499 if (transport_account) {
1500 ModestTnySendQueue *send_queue;
1504 send_queue = modest_runtime_get_send_queue (transport_account);
1506 /* Get outbox folder */
1507 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1508 num_messages = tny_folder_get_all_count (outbox);
1509 g_object_unref (outbox);
1511 if (num_messages == 0) {
1512 end_operation = TRUE;
1514 UpdateAccountSendQueueFlushInfo *send_info;
1516 end_operation = FALSE;
1519 priv->total = num_messages;
1520 g_object_unref (priv->account);
1521 priv->account = TNY_ACCOUNT (transport_account);
1523 /* Create the info object */
1524 send_info = g_slice_new (UpdateAccountSendQueueFlushInfo);
1525 send_info->error_handler = g_signal_connect (send_queue, "error-happened",
1526 G_CALLBACK (update_account_on_error_happened_cb),
1528 send_info->sent_handler = g_signal_connect (send_queue, "msg-sent",
1529 G_CALLBACK (update_account_on_msg_sent_cb),
1531 send_info->mail_op = g_object_ref (info->mail_op);
1533 /* Reenable suspended items */
1534 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1537 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1540 end_operation = TRUE;
1543 /* Check if the operation was a success */
1545 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1547 /* Set the account back to not busy */
1548 modest_account_mgr_set_account_busy (mgr, info->account_name, FALSE);
1550 /* Call the user callback */
1552 info->callback (info->mail_op, new_headers, info->user_data);
1554 /* Notify about operation end */
1556 modest_mail_operation_notify_end (info->mail_op);
1560 g_object_unref (new_headers);
1561 destroy_update_account_info (info);
1565 recurse_folders_async_cb (TnyFolderStore *folder_store,
1571 UpdateAccountInfo *info;
1572 ModestMailOperationPrivate *priv;
1574 info = (UpdateAccountInfo *) user_data;
1575 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1577 if (err || canceled) {
1578 /* Try to continue anyway */
1580 TnyIterator *iter = tny_list_create_iterator (list);
1581 while (!tny_iterator_is_done (iter)) {
1582 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1583 TnyList *folders = tny_simple_list_new ();
1585 /* Add to the list of all folders */
1586 tny_list_append (info->folders, (GObject *) folder);
1588 /* Add pending call */
1589 info->pending_calls++;
1591 tny_folder_store_get_folders_async (folder, folders, NULL,
1592 recurse_folders_async_cb,
1595 g_object_unref (G_OBJECT (folder));
1597 tny_iterator_next (iter);
1599 g_object_unref (G_OBJECT (iter));
1600 g_object_unref (G_OBJECT (list));
1603 /* Remove my own pending call */
1604 info->pending_calls--;
1606 /* This means that we have all the folders */
1607 if (info->pending_calls == 0) {
1608 TnyIterator *iter_all_folders;
1609 TnyFolder *inbox = NULL;
1611 iter_all_folders = tny_list_create_iterator (info->folders);
1613 /* Do a poke status over all folders */
1614 while (!tny_iterator_is_done (iter_all_folders) &&
1615 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1616 TnyFolder *folder = NULL;
1618 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1620 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1621 /* Get a reference to the INBOX */
1622 inbox = g_object_ref (folder);
1624 /* Issue a poke status over the folder */
1626 tny_folder_poke_status (folder);
1629 /* Free and go to next */
1630 g_object_unref (folder);
1631 tny_iterator_next (iter_all_folders);
1633 g_object_unref (iter_all_folders);
1635 /* Refresh the INBOX */
1637 /* Refresh the folder. Our observer receives
1638 * the new emails during folder refreshes, so
1639 * we can use observer->new_headers
1641 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1642 tny_folder_add_observer (inbox, info->inbox_observer);
1644 /* Refresh the INBOX */
1645 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1646 g_object_unref (inbox);
1648 /* We could not perform the inbox refresh but
1649 we'll try to send mails anyway */
1650 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1656 modest_mail_operation_update_account (ModestMailOperation *self,
1657 const gchar *account_name,
1659 RetrieveAllCallback retrieve_all_cb,
1660 UpdateAccountCallback callback,
1663 UpdateAccountInfo *info = NULL;
1664 ModestMailOperationPrivate *priv = NULL;
1665 ModestTnyAccountStore *account_store = NULL;
1666 TnyStoreAccount *store_account = NULL;
1668 ModestMailOperationState *state;
1670 /* Init mail operation */
1671 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1674 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1675 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1677 /* Get the store account */
1678 account_store = modest_runtime_get_account_store ();
1679 store_account = (TnyStoreAccount *)
1680 modest_tny_account_store_get_server_account (account_store,
1682 TNY_ACCOUNT_TYPE_STORE);
1683 priv->account = g_object_ref (store_account);
1685 /* Create the helper object */
1686 info = g_slice_new0 (UpdateAccountInfo);
1687 info->pending_calls = 1;
1688 info->folders = tny_simple_list_new ();
1689 info->mail_op = g_object_ref (self);
1690 info->poke_all = poke_all;
1691 info->account_name = g_strdup (account_name);
1692 info->callback = callback;
1693 info->user_data = user_data;
1694 info->retrieve_all_cb = retrieve_all_cb;
1696 /* Set account busy */
1697 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1698 modest_mail_operation_notify_start (self);
1700 /* notify about the start of the operation */
1701 state = modest_mail_operation_clone_state (self);
1705 /* Start notifying progress */
1706 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1707 g_slice_free (ModestMailOperationState, state);
1709 /* Get all folders and continue in the callback */
1710 folders = tny_simple_list_new ();
1711 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (store_account),
1713 recurse_folders_async_cb,
1718 * Used to notify the queue from the main
1719 * loop. We call it inside an idle call to achieve that
1722 idle_notify_queue (gpointer data)
1724 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1726 gdk_threads_enter ();
1727 modest_mail_operation_notify_end (mail_op);
1728 gdk_threads_leave ();
1729 g_object_unref (mail_op);
1735 compare_headers_by_date (gconstpointer a,
1738 TnyHeader **header1, **header2;
1739 time_t sent1, sent2;
1741 header1 = (TnyHeader **) a;
1742 header2 = (TnyHeader **) b;
1744 sent1 = tny_header_get_date_sent (*header1);
1745 sent2 = tny_header_get_date_sent (*header2);
1747 /* We want the most recent ones (greater time_t) at the
1756 /* ******************************************************************* */
1757 /* ************************** STORE ACTIONS ************************* */
1758 /* ******************************************************************* */
1761 ModestMailOperation *mail_op;
1762 CreateFolderUserCallback callback;
1768 create_folder_cb (TnyFolderStore *parent_folder,
1770 TnyFolder *new_folder,
1774 ModestMailOperationPrivate *priv;
1775 CreateFolderInfo *info;
1777 info = (CreateFolderInfo *) user_data;
1778 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1780 if (canceled || err) {
1781 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1783 priv->error = g_error_copy (err);
1785 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1786 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1789 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1792 /* The user will unref the new_folder */
1794 info->callback (info->mail_op, parent_folder,
1795 new_folder, info->user_data);
1797 /* Notify about operation end */
1798 modest_mail_operation_notify_end (info->mail_op);
1801 g_object_unref (info->mail_op);
1802 g_slice_free (CreateFolderInfo, info);
1806 modest_mail_operation_create_folder (ModestMailOperation *self,
1807 TnyFolderStore *parent,
1809 CreateFolderUserCallback callback,
1812 ModestMailOperationPrivate *priv;
1814 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1815 g_return_if_fail (name);
1817 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1818 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1819 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1820 g_object_ref (parent) :
1821 modest_tny_folder_get_account (TNY_FOLDER (parent));
1823 /* Check for already existing folder */
1824 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1825 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1826 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1827 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1828 _CS("ckdg_ib_folder_already_exists"));
1832 if (TNY_IS_FOLDER (parent)) {
1833 /* Check folder rules */
1834 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1835 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1836 /* Set status failed and set an error */
1837 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1838 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1839 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1840 _("mail_in_ui_folder_create_error"));
1844 if (!strcmp (name, " ") || strchr (name, '/')) {
1845 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1846 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1847 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1848 _("mail_in_ui_folder_create_error"));
1852 CreateFolderInfo *info;
1854 info = g_slice_new0 (CreateFolderInfo);
1855 info->mail_op = g_object_ref (self);
1856 info->callback = callback;
1857 info->user_data = user_data;
1859 modest_mail_operation_notify_start (self);
1861 /* Create the folder */
1862 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1865 /* Call the user callback anyway */
1867 callback (self, parent, NULL, user_data);
1868 /* Notify about operation end */
1869 modest_mail_operation_notify_end (self);
1874 modest_mail_operation_remove_folder (ModestMailOperation *self,
1876 gboolean remove_to_trash)
1878 TnyAccount *account;
1879 ModestMailOperationPrivate *priv;
1880 ModestTnyFolderRules rules;
1882 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1883 g_return_if_fail (TNY_IS_FOLDER (folder));
1885 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1887 /* Check folder rules */
1888 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1889 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1890 /* Set status failed and set an error */
1891 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1892 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1893 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1894 _("mail_in_ui_folder_delete_error"));
1898 /* Get the account */
1899 account = modest_tny_folder_get_account (folder);
1900 priv->account = g_object_ref(account);
1901 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1903 /* Delete folder or move to trash */
1904 if (remove_to_trash) {
1905 TnyFolder *trash_folder = NULL;
1906 trash_folder = modest_tny_account_get_special_folder (account,
1907 TNY_FOLDER_TYPE_TRASH);
1908 /* TODO: error_handling */
1910 modest_mail_operation_notify_start (self);
1911 modest_mail_operation_xfer_folder (self, folder,
1912 TNY_FOLDER_STORE (trash_folder),
1914 g_object_unref (trash_folder);
1916 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1919 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1921 modest_mail_operation_notify_start (self);
1922 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1923 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1926 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1928 g_object_unref (parent);
1930 g_warning ("%s: could not get parent folder", __FUNCTION__);
1932 g_object_unref (G_OBJECT (account));
1935 /* Notify about operation end */
1936 modest_mail_operation_notify_end (self);
1940 transfer_folder_status_cb (GObject *obj,
1944 ModestMailOperation *self;
1945 ModestMailOperationPrivate *priv;
1946 ModestMailOperationState *state;
1947 XFerFolderAsyncHelper *helper;
1949 g_return_if_fail (status != NULL);
1950 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1952 helper = (XFerFolderAsyncHelper *) user_data;
1953 g_return_if_fail (helper != NULL);
1955 self = helper->mail_op;
1956 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1958 priv->done = status->position;
1959 priv->total = status->of_total;
1961 state = modest_mail_operation_clone_state (self);
1963 /* This is not a GDK lock because we are a Tinymail callback
1964 * which is already GDK locked by Tinymail */
1966 /* no gdk_threads_enter (), CHECKED */
1968 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1970 /* no gdk_threads_leave (), CHECKED */
1972 g_slice_free (ModestMailOperationState, state);
1977 transfer_folder_cb (TnyFolder *folder,
1979 TnyFolderStore *into,
1980 TnyFolder *new_folder,
1984 XFerFolderAsyncHelper *helper;
1985 ModestMailOperation *self = NULL;
1986 ModestMailOperationPrivate *priv = NULL;
1988 helper = (XFerFolderAsyncHelper *) user_data;
1989 g_return_if_fail (helper != NULL);
1991 self = helper->mail_op;
1992 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1995 priv->error = g_error_copy (err);
1997 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1998 } else if (cancelled) {
1999 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2000 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2001 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2002 _("Transference of %s was cancelled."),
2003 tny_folder_get_name (folder));
2006 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2009 /* Notify about operation end */
2010 modest_mail_operation_notify_end (self);
2012 /* If user defined callback function was defined, call it */
2013 if (helper->user_callback) {
2015 /* This is not a GDK lock because we are a Tinymail callback
2016 * which is already GDK locked by Tinymail */
2018 /* no gdk_threads_enter (), CHECKED */
2019 helper->user_callback (self, new_folder, helper->user_data);
2020 /* no gdk_threads_leave () , CHECKED */
2024 g_object_unref (helper->mail_op);
2025 g_slice_free (XFerFolderAsyncHelper, helper);
2030 * This function checks if the new name is a valid name for our local
2031 * folders account. The new name could not be the same than then name
2032 * of any of the mandatory local folders
2034 * We can not rely on tinymail because tinymail does not check the
2035 * name of the virtual folders that the account could have in the case
2036 * that we're doing a rename (because it directly calls Camel which
2037 * knows nothing about our virtual folders).
2039 * In the case of an actual copy/move (i.e. move/copy a folder between
2040 * accounts) tinymail uses the tny_folder_store_create_account which
2041 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2042 * checks the new name of the folder, so this call in that case
2043 * wouldn't be needed. *But* NOTE that if tinymail changes its
2044 * implementation (if folder transfers within the same account is no
2045 * longer implemented as a rename) this call will allow Modest to work
2048 * If the new name is not valid, this function will set the status to
2049 * failed and will set also an error in the mail operation
2052 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2053 TnyFolderStore *into,
2054 const gchar *new_name)
2056 if (TNY_IS_ACCOUNT (into) &&
2057 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2058 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2060 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2061 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2062 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2063 _CS("ckdg_ib_folder_already_exists"));
2070 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2072 TnyFolderStore *parent,
2073 gboolean delete_original,
2074 XferFolderAsyncUserCallback user_callback,
2077 ModestMailOperationPrivate *priv = NULL;
2078 ModestTnyFolderRules parent_rules = 0, rules;
2079 XFerFolderAsyncHelper *helper = NULL;
2080 const gchar *folder_name = NULL;
2081 const gchar *error_msg;
2083 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2084 g_return_if_fail (TNY_IS_FOLDER (folder));
2085 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2087 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2088 folder_name = tny_folder_get_name (folder);
2090 /* Set the error msg */
2091 error_msg = _("mail_in_ui_folder_move_target_error");
2093 /* Get account and set it into mail_operation */
2094 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2095 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2096 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2098 /* Get folder rules */
2099 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2100 if (TNY_IS_FOLDER (parent))
2101 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2103 /* Apply operation constraints */
2104 if ((gpointer) parent == (gpointer) folder ||
2105 (!TNY_IS_FOLDER_STORE (parent)) ||
2106 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2109 } else if (TNY_IS_FOLDER (parent) &&
2110 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2114 } else if (TNY_IS_FOLDER (parent) &&
2115 TNY_IS_FOLDER_STORE (folder) &&
2116 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2117 TNY_FOLDER_STORE (folder))) {
2118 /* Do not move a parent into a child */
2120 } else if (TNY_IS_FOLDER_STORE (parent) &&
2121 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2122 /* Check that the new folder name is not used by any
2125 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2126 /* Check that the new folder name is not used by any
2127 special local folder */
2130 /* Create the helper */
2131 helper = g_slice_new0 (XFerFolderAsyncHelper);
2132 helper->mail_op = g_object_ref (self);
2133 helper->user_callback = user_callback;
2134 helper->user_data = user_data;
2136 /* Move/Copy folder */
2137 modest_mail_operation_notify_start (self);
2138 tny_folder_copy_async (folder,
2140 tny_folder_get_name (folder),
2143 transfer_folder_status_cb,
2149 /* Set status failed and set an error */
2150 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2151 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2152 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2155 /* Call the user callback if exists */
2157 user_callback (self, NULL, user_data);
2159 /* Notify the queue */
2160 modest_mail_operation_notify_end (self);
2164 modest_mail_operation_rename_folder (ModestMailOperation *self,
2167 XferFolderAsyncUserCallback user_callback,
2170 ModestMailOperationPrivate *priv;
2171 ModestTnyFolderRules rules;
2172 XFerFolderAsyncHelper *helper;
2174 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2175 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2176 g_return_if_fail (name);
2178 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2180 /* Get account and set it into mail_operation */
2181 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2182 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2184 /* Check folder rules */
2185 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2186 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2188 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2191 TnyFolderStore *into;
2193 into = tny_folder_get_folder_store (folder);
2195 /* Check that the new folder name is not used by any
2196 special local folder */
2197 if (new_name_valid_if_local_account (priv, into, name)) {
2198 /* Create the helper */
2199 helper = g_slice_new0 (XFerFolderAsyncHelper);
2200 helper->mail_op = g_object_ref(self);
2201 helper->user_callback = user_callback;
2202 helper->user_data = user_data;
2204 /* Rename. Camel handles folder subscription/unsubscription */
2205 modest_mail_operation_notify_start (self);
2206 tny_folder_copy_async (folder, into, name, TRUE,
2208 transfer_folder_status_cb,
2213 g_object_unref (into);
2218 /* Set status failed and set an error */
2219 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2220 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2221 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2222 _("FIXME: unable to rename"));
2225 user_callback (self, NULL, user_data);
2227 /* Notify about operation end */
2228 modest_mail_operation_notify_end (self);
2231 /* ******************************************************************* */
2232 /* ************************** MSG ACTIONS ************************* */
2233 /* ******************************************************************* */
2236 modest_mail_operation_get_msg (ModestMailOperation *self,
2238 GetMsgAsyncUserCallback user_callback,
2241 GetMsgInfo *helper = NULL;
2243 ModestMailOperationPrivate *priv;
2245 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2246 g_return_if_fail (TNY_IS_HEADER (header));
2248 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2249 folder = tny_header_get_folder (header);
2251 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2255 /* Get account and set it into mail_operation */
2256 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2258 /* Check for cached messages */
2259 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2260 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2262 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2264 /* Create the helper */
2265 helper = g_slice_new0 (GetMsgInfo);
2266 helper->header = g_object_ref (header);
2267 helper->mail_op = g_object_ref (self);
2268 helper->user_callback = user_callback;
2269 helper->user_data = user_data;
2270 helper->destroy_notify = NULL;
2271 helper->last_total_bytes = 0;
2272 helper->sum_total_bytes = 0;
2273 helper->total_bytes = tny_header_get_message_size (header);
2275 modest_mail_operation_notify_start (self);
2277 /* notify about the start of the operation */
2278 ModestMailOperationState *state;
2279 state = modest_mail_operation_clone_state (self);
2282 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2285 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2287 g_object_unref (G_OBJECT (folder));
2291 get_msg_status_cb (GObject *obj,
2295 GetMsgInfo *helper = NULL;
2297 g_return_if_fail (status != NULL);
2298 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2300 helper = (GetMsgInfo *) user_data;
2301 g_return_if_fail (helper != NULL);
2303 /* Notify progress */
2304 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2305 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2309 get_msg_async_cb (TnyFolder *folder,
2315 GetMsgInfo *info = NULL;
2316 ModestMailOperationPrivate *priv = NULL;
2319 info = (GetMsgInfo *) user_data;
2321 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2323 finished = (priv->done == priv->total) ? TRUE : FALSE;
2326 if (canceled || err) {
2327 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2329 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2330 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2333 /* Set the success status before calling the user callback */
2334 if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2335 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2339 /* Call the user callback */
2340 if (info->user_callback)
2341 info->user_callback (info->mail_op, info->header, canceled,
2342 msg, err, info->user_data);
2344 /* Notify about operation end if this is the last callback */
2346 /* Free user data */
2347 if (info->destroy_notify)
2348 info->destroy_notify (info->user_data);
2350 /* Notify about operation end */
2351 modest_mail_operation_notify_end (info->mail_op);
2355 g_object_unref (info->header);
2356 g_object_unref (info->mail_op);
2357 g_slice_free (GetMsgInfo, info);
2361 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2362 TnyList *header_list,
2363 GetMsgAsyncUserCallback user_callback,
2365 GDestroyNotify notify)
2367 ModestMailOperationPrivate *priv = NULL;
2369 TnyIterator *iter = NULL;
2371 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2373 /* Init mail operation */
2374 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2375 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2376 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2378 priv->total = tny_list_get_length(header_list);
2380 /* Get account and set it into mail_operation */
2381 if (tny_list_get_length (header_list) >= 1) {
2382 iter = tny_list_create_iterator (header_list);
2383 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2385 TnyFolder *folder = tny_header_get_folder (header);
2387 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2388 g_object_unref (folder);
2390 g_object_unref (header);
2393 if (tny_list_get_length (header_list) == 1) {
2394 g_object_unref (iter);
2399 msg_list_size = compute_message_list_size (header_list);
2401 modest_mail_operation_notify_start (self);
2402 iter = tny_list_create_iterator (header_list);
2403 while (!tny_iterator_is_done (iter)) {
2404 /* notify about the start of the operation */
2405 ModestMailOperationState *state;
2406 state = modest_mail_operation_clone_state (self);
2409 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2412 GetMsgInfo *msg_info = NULL;
2413 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2414 TnyFolder *folder = tny_header_get_folder (header);
2416 /* Create the message info */
2417 msg_info = g_slice_new0 (GetMsgInfo);
2418 msg_info->mail_op = g_object_ref (self);
2419 msg_info->header = g_object_ref (header);
2420 msg_info->user_callback = user_callback;
2421 msg_info->user_data = user_data;
2422 msg_info->destroy_notify = notify;
2423 msg_info->last_total_bytes = 0;
2424 msg_info->sum_total_bytes = 0;
2425 msg_info->total_bytes = msg_list_size;
2427 /* The callback will call it per each header */
2428 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2430 /* Free and go on */
2431 g_object_unref (header);
2432 g_object_unref (folder);
2433 tny_iterator_next (iter);
2435 g_object_unref (iter);
2440 modest_mail_operation_remove_msg (ModestMailOperation *self,
2442 gboolean remove_to_trash /*ignored*/)
2445 ModestMailOperationPrivate *priv;
2447 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2448 g_return_if_fail (TNY_IS_HEADER (header));
2450 if (remove_to_trash)
2451 g_warning ("remove to trash is not implemented");
2453 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2454 folder = tny_header_get_folder (header);
2456 /* Get account and set it into mail_operation */
2457 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2458 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2459 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2461 /* remove message from folder */
2462 tny_folder_remove_msg (folder, header, &(priv->error));
2464 gboolean expunge, leave_on_server;
2465 const gchar *account_name;
2466 TnyAccount *account;
2467 ModestTransportStoreProtocol account_proto;
2469 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2470 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2472 modest_mail_operation_notify_start (self);
2474 /* Get leave on server setting */
2475 account = tny_folder_get_account (folder);
2476 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2478 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2481 account_proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
2483 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2484 modest_tny_folder_is_remote_folder (folder) == FALSE)
2490 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2493 g_object_unref (account);
2499 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2501 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2504 g_object_unref (G_OBJECT (folder));
2506 /* Notify about operation end */
2507 modest_mail_operation_notify_end (self);
2511 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2513 gboolean remove_to_trash /*ignored*/)
2515 TnyFolder *folder = NULL;
2516 ModestMailOperationPrivate *priv;
2517 TnyIterator *iter = NULL;
2518 TnyHeader *header = NULL;
2519 TnyList *remove_headers = NULL;
2520 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2522 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2523 g_return_if_fail (TNY_IS_LIST (headers));
2525 if (remove_to_trash)
2526 g_warning ("remove to trash is not implemented");
2528 if (tny_list_get_length(headers) == 0) {
2529 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2530 goto cleanup; /* nothing to do */
2533 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2534 remove_headers = g_object_ref(headers);
2536 /* Get folder from first header and sync it */
2537 iter = tny_list_create_iterator (headers);
2538 header = TNY_HEADER (tny_iterator_get_current (iter));
2540 folder = tny_header_get_folder (header);
2541 if (!TNY_IS_FOLDER(folder)) {
2542 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2546 /* Don't remove messages that are being sent */
2547 if (modest_tny_folder_is_local_folder (folder)) {
2548 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2550 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2551 TnyTransportAccount *traccount = NULL;
2552 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2553 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2555 ModestTnySendQueueStatus status;
2556 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2557 TnyIterator *iter = tny_list_create_iterator(headers);
2558 g_object_unref(remove_headers);
2559 remove_headers = TNY_LIST(tny_simple_list_new());
2560 while (!tny_iterator_is_done(iter)) {
2562 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2563 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2564 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2565 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2566 tny_list_append(remove_headers, G_OBJECT(hdr));
2568 g_object_unref(hdr);
2570 tny_iterator_next(iter);
2572 g_object_unref(iter);
2573 g_object_unref(traccount);
2577 /* Get account and set it into mail_operation */
2578 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2579 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2580 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2582 /* remove message from folder */
2583 modest_mail_operation_notify_start (self);
2585 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2587 gboolean expunge, leave_on_server;
2588 const gchar *account_name;
2590 TnyAccount *account;
2591 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2593 account = tny_folder_get_account (folder);
2594 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2596 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2599 proto = tny_account_get_proto (account);
2601 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2604 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2605 modest_tny_folder_is_remote_folder (folder) == FALSE)
2611 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2613 g_object_unref (account);
2619 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2621 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2626 g_object_unref (remove_headers);
2628 g_object_unref (header);
2630 g_object_unref (iter);
2632 g_object_unref (folder);
2634 /* Notify about operation end */
2635 modest_mail_operation_notify_end (self);
2639 notify_progress_of_multiple_messages (ModestMailOperation *self,
2641 gint *last_total_bytes,
2642 gint *sum_total_bytes,
2644 gboolean increment_done)
2646 ModestMailOperationPrivate *priv;
2647 ModestMailOperationState *state;
2648 gboolean is_num_bytes = FALSE;
2650 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2652 /* We know that tinymail sends us information about
2653 * transferred bytes with this particular message
2655 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2656 * I just added the 'if' so we don't get runtime warning)
2658 if (status->message)
2659 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2661 state = modest_mail_operation_clone_state (self);
2662 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2663 /* We know that we're in a different message when the
2664 total number of bytes to transfer is different. Of
2665 course it could fail if we're transferring messages
2666 of the same size, but this is a workarround */
2667 if (status->of_total != *last_total_bytes) {
2668 /* We need to increment the done when there is
2669 no information about each individual
2670 message, we need to do this in message
2671 transfers, and we don't do it for getting
2675 *sum_total_bytes += *last_total_bytes;
2676 *last_total_bytes = status->of_total;
2678 state->bytes_done += status->position + *sum_total_bytes;
2679 state->bytes_total = total_bytes;
2681 /* Notify the status change. Only notify about changes
2682 referred to bytes */
2683 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2687 g_slice_free (ModestMailOperationState, state);
2691 transfer_msgs_status_cb (GObject *obj,
2695 XFerMsgsAsyncHelper *helper;
2697 g_return_if_fail (status != NULL);
2698 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2700 helper = (XFerMsgsAsyncHelper *) user_data;
2701 g_return_if_fail (helper != NULL);
2703 /* Notify progress */
2704 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2705 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2710 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2712 XFerMsgsAsyncHelper *helper;
2713 ModestMailOperation *self;
2714 ModestMailOperationPrivate *priv;
2715 TnyIterator *iter = NULL;
2716 TnyHeader *header = NULL;
2718 helper = (XFerMsgsAsyncHelper *) user_data;
2719 self = helper->mail_op;
2721 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2724 priv->error = g_error_copy (err);
2726 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2727 } else if (cancelled) {
2728 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2729 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2730 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2731 _("Error trying to refresh the contents of %s"),
2732 tny_folder_get_name (folder));
2735 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2737 /* Update folder counts */
2738 tny_folder_poke_status (folder);
2739 tny_folder_poke_status (helper->dest_folder);
2743 /* Mark headers as deleted and seen */
2744 if ((helper->delete) &&
2745 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2746 iter = tny_list_create_iterator (helper->headers);
2747 while (!tny_iterator_is_done (iter)) {
2748 header = TNY_HEADER (tny_iterator_get_current (iter));
2749 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2750 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2751 g_object_unref (header);
2753 tny_iterator_next (iter);
2758 /* Notify about operation end */
2759 modest_mail_operation_notify_end (self);
2761 /* If user defined callback function was defined, call it */
2762 if (helper->user_callback) {
2763 /* This is not a GDK lock because we are a Tinymail callback and
2764 * Tinymail already acquires the Gdk lock */
2766 /* no gdk_threads_enter (), CHECKED */
2767 helper->user_callback (self, helper->user_data);
2768 /* no gdk_threads_leave (), CHECKED */
2772 if (helper->headers)
2773 g_object_unref (helper->headers);
2774 if (helper->dest_folder)
2775 g_object_unref (helper->dest_folder);
2776 if (helper->mail_op)
2777 g_object_unref (helper->mail_op);
2779 g_object_unref (folder);
2781 g_object_unref (iter);
2782 g_slice_free (XFerMsgsAsyncHelper, helper);
2786 compute_message_list_size (TnyList *headers)
2791 iter = tny_list_create_iterator (headers);
2792 while (!tny_iterator_is_done (iter)) {
2793 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2794 size += tny_header_get_message_size (header);
2795 g_object_unref (header);
2796 tny_iterator_next (iter);
2798 g_object_unref (iter);
2804 compute_message_array_size (GPtrArray *headers)
2809 for (i = 0; i < headers->len; i++) {
2810 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2811 size += tny_header_get_message_size (header);
2819 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2822 gboolean delete_original,
2823 XferMsgsAsyncUserCallback user_callback,
2826 ModestMailOperationPrivate *priv = NULL;
2827 TnyIterator *iter = NULL;
2828 TnyFolder *src_folder = NULL;
2829 XFerMsgsAsyncHelper *helper = NULL;
2830 TnyHeader *header = NULL;
2831 ModestTnyFolderRules rules = 0;
2833 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2834 g_return_if_fail (headers && TNY_IS_LIST (headers));
2835 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2837 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2838 priv->total = tny_list_get_length (headers);
2840 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2841 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2843 /* Apply folder rules */
2844 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2845 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2846 /* Set status failed and set an error */
2847 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2848 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2849 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2850 _CS("ckct_ib_unable_to_paste_here"));
2851 /* Notify the queue */
2852 modest_mail_operation_notify_end (self);
2856 /* Get source folder */
2857 iter = tny_list_create_iterator (headers);
2858 header = TNY_HEADER (tny_iterator_get_current (iter));
2860 src_folder = tny_header_get_folder (header);
2861 g_object_unref (header);
2863 g_object_unref (iter);
2865 if (src_folder == NULL) {
2866 /* Notify the queue */
2867 modest_mail_operation_notify_end (self);
2869 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2874 /* Check folder source and destination */
2875 if (src_folder == folder) {
2876 /* Set status failed and set an error */
2877 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2878 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2879 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2880 _("mail_in_ui_folder_copy_target_error"));
2882 /* Notify the queue */
2883 modest_mail_operation_notify_end (self);
2886 g_object_unref (src_folder);
2890 /* Create the helper */
2891 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2892 helper->mail_op = g_object_ref(self);
2893 helper->dest_folder = g_object_ref(folder);
2894 helper->headers = g_object_ref(headers);
2895 helper->user_callback = user_callback;
2896 helper->user_data = user_data;
2897 helper->delete = delete_original;
2898 helper->last_total_bytes = 0;
2899 helper->sum_total_bytes = 0;
2900 helper->total_bytes = compute_message_list_size (headers);
2902 /* Get account and set it into mail_operation */
2903 priv->account = modest_tny_folder_get_account (src_folder);
2905 /* Transfer messages */
2906 modest_mail_operation_notify_start (self);
2907 tny_folder_transfer_msgs_async (src_folder,
2912 transfer_msgs_status_cb,
2918 on_refresh_folder (TnyFolder *folder,
2923 RefreshAsyncHelper *helper = NULL;
2924 ModestMailOperation *self = NULL;
2925 ModestMailOperationPrivate *priv = NULL;
2927 helper = (RefreshAsyncHelper *) user_data;
2928 self = helper->mail_op;
2929 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2931 g_return_if_fail(priv!=NULL);
2934 priv->error = g_error_copy (error);
2935 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2940 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2941 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2942 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2943 _("Error trying to refresh the contents of %s"),
2944 tny_folder_get_name (folder));
2948 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2951 /* Call user defined callback, if it exists */
2952 if (helper->user_callback) {
2954 /* This is not a GDK lock because we are a Tinymail callback and
2955 * Tinymail already acquires the Gdk lock */
2956 helper->user_callback (self, folder, helper->user_data);
2960 g_slice_free (RefreshAsyncHelper, helper);
2962 /* Notify about operation end */
2963 modest_mail_operation_notify_end (self);
2964 g_object_unref(self);
2968 on_refresh_folder_status_update (GObject *obj,
2972 RefreshAsyncHelper *helper = NULL;
2973 ModestMailOperation *self = NULL;
2974 ModestMailOperationPrivate *priv = NULL;
2975 ModestMailOperationState *state;
2977 g_return_if_fail (user_data != NULL);
2978 g_return_if_fail (status != NULL);
2979 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2981 helper = (RefreshAsyncHelper *) user_data;
2982 self = helper->mail_op;
2983 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2985 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2987 priv->done = status->position;
2988 priv->total = status->of_total;
2990 state = modest_mail_operation_clone_state (self);
2992 /* This is not a GDK lock because we are a Tinymail callback and
2993 * Tinymail already acquires the Gdk lock */
2994 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2996 g_slice_free (ModestMailOperationState, state);
3000 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3002 RefreshAsyncUserCallback user_callback,
3005 ModestMailOperationPrivate *priv = NULL;
3006 RefreshAsyncHelper *helper = NULL;
3008 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3010 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3012 /* Get account and set it into mail_operation */
3013 priv->account = modest_tny_folder_get_account (folder);
3014 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3016 /* Create the helper */
3017 helper = g_slice_new0 (RefreshAsyncHelper);
3018 helper->mail_op = g_object_ref(self);
3019 helper->user_callback = user_callback;
3020 helper->user_data = user_data;
3022 /* Refresh the folder. TODO: tinymail could issue a status
3023 updates before the callback call then this could happen. We
3024 must review the design */
3025 modest_mail_operation_notify_start (self);
3027 /* notify that the operation was started */
3028 ModestMailOperationState *state;
3029 state = modest_mail_operation_clone_state (self);
3032 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3035 tny_folder_refresh_async (folder,
3037 on_refresh_folder_status_update,
3043 modest_mail_operation_notify_start (ModestMailOperation *self)
3045 ModestMailOperationPrivate *priv = NULL;
3047 g_return_if_fail (self);
3049 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3051 /* Ensure that all the fields are filled correctly */
3052 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3054 /* Notify the observers about the mail operation. We do not
3055 wrapp this emission because we assume that this function is
3056 always called from within the main lock */
3057 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3062 * It's used by the mail operation queue to notify the observers
3063 * attached to that signal that the operation finished. We need to use
3064 * that because tinymail does not give us the progress of a given
3065 * operation when it finishes (it directly calls the operation
3069 modest_mail_operation_notify_end (ModestMailOperation *self)
3071 ModestMailOperationPrivate *priv = NULL;
3073 g_return_if_fail (self);
3075 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3077 /* Notify the observers about the mail operation end. We do
3078 not wrapp this emission because we assume that this
3079 function is always called from within the main lock */
3080 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3082 /* Remove the error user data */
3083 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3084 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3088 modest_mail_operation_get_account (ModestMailOperation *self)
3090 ModestMailOperationPrivate *priv = NULL;
3092 g_return_val_if_fail (self, NULL);
3094 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3096 return (priv->account) ? g_object_ref (priv->account) : NULL;
3100 modest_mail_operation_noop (ModestMailOperation *self)
3102 ModestMailOperationPrivate *priv = NULL;
3104 g_return_if_fail (self);
3106 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3107 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3108 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3112 /* This mail operation does nothing actually */
3113 modest_mail_operation_notify_start (self);
3114 modest_mail_operation_notify_end (self);
3119 modest_mail_operation_to_string (ModestMailOperation *self)
3121 const gchar *type, *status, *account_id;
3122 ModestMailOperationPrivate *priv = NULL;
3124 g_return_val_if_fail (self, NULL);
3126 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3128 /* new operations don't have anything interesting */
3129 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3130 return g_strdup_printf ("%p <new operation>", self);
3132 switch (priv->op_type) {
3133 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3134 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3135 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3136 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3137 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3138 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3139 default: type = "UNEXPECTED"; break;
3142 switch (priv->status) {
3143 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3144 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3145 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3146 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3147 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3148 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3149 default: status= "UNEXPECTED"; break;
3152 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3154 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3155 priv->done, priv->total,
3156 priv->error && priv->error->message ? priv->error->message : "");