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-simple-list.h>
41 #include <tny-send-queue.h>
42 #include <tny-status.h>
43 #include <tny-folder-observer.h>
44 #include <camel/camel-stream-mem.h>
45 #include <glib/gi18n.h>
46 #include "modest-platform.h"
47 #include <modest-tny-account.h>
48 #include <modest-tny-send-queue.h>
49 #include <modest-runtime.h>
50 #include "modest-text-utils.h"
51 #include "modest-tny-msg.h"
52 #include "modest-tny-folder.h"
53 #include "modest-tny-platform-factory.h"
54 #include "modest-marshal.h"
55 #include "modest-error.h"
56 #include "modest-mail-operation.h"
60 /* 'private'/'protected' functions */
61 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
62 static void modest_mail_operation_init (ModestMailOperation *obj);
63 static void modest_mail_operation_finalize (GObject *obj);
65 static void get_msg_cb (TnyFolder *folder,
71 static void get_msg_status_cb (GObject *obj,
75 static void modest_mail_operation_notify_end (ModestMailOperation *self);
77 static gboolean did_a_cancel = FALSE;
79 enum _ModestMailOperationSignals
81 PROGRESS_CHANGED_SIGNAL,
86 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
87 struct _ModestMailOperationPrivate {
94 ErrorCheckingUserCallback error_checking;
95 gpointer error_checking_user_data;
96 ModestMailOperationStatus status;
97 ModestMailOperationTypeOperation op_type;
100 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
101 MODEST_TYPE_MAIL_OPERATION, \
102 ModestMailOperationPrivate))
104 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
105 priv->status = new_status;\
108 typedef struct _GetMsgAsyncHelper {
109 ModestMailOperation *mail_op;
111 GetMsgAsyncUserCallback user_callback;
115 typedef struct _RefreshAsyncHelper {
116 ModestMailOperation *mail_op;
117 RefreshAsyncUserCallback user_callback;
119 } RefreshAsyncHelper;
121 typedef struct _XFerMsgAsyncHelper
123 ModestMailOperation *mail_op;
125 TnyFolder *dest_folder;
126 XferMsgsAsynUserCallback user_callback;
128 } XFerMsgAsyncHelper;
131 static GObjectClass *parent_class = NULL;
133 static guint signals[NUM_SIGNALS] = {0};
136 modest_mail_operation_get_type (void)
138 static GType my_type = 0;
140 static const GTypeInfo my_info = {
141 sizeof(ModestMailOperationClass),
142 NULL, /* base init */
143 NULL, /* base finalize */
144 (GClassInitFunc) modest_mail_operation_class_init,
145 NULL, /* class finalize */
146 NULL, /* class data */
147 sizeof(ModestMailOperation),
149 (GInstanceInitFunc) modest_mail_operation_init,
152 my_type = g_type_register_static (G_TYPE_OBJECT,
153 "ModestMailOperation",
160 modest_mail_operation_class_init (ModestMailOperationClass *klass)
162 GObjectClass *gobject_class;
163 gobject_class = (GObjectClass*) klass;
165 parent_class = g_type_class_peek_parent (klass);
166 gobject_class->finalize = modest_mail_operation_finalize;
168 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
171 * ModestMailOperation::progress-changed
172 * @self: the #MailOperation that emits the signal
173 * @user_data: user data set when the signal handler was connected
175 * Emitted when the progress of a mail operation changes
177 signals[PROGRESS_CHANGED_SIGNAL] =
178 g_signal_new ("progress-changed",
179 G_TYPE_FROM_CLASS (gobject_class),
181 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
183 g_cclosure_marshal_VOID__POINTER,
184 G_TYPE_NONE, 1, G_TYPE_POINTER);
189 modest_mail_operation_init (ModestMailOperation *obj)
191 ModestMailOperationPrivate *priv;
193 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
195 priv->account = NULL;
196 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
197 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
202 priv->error_checking = NULL;
203 priv->error_checking_user_data = NULL;
207 modest_mail_operation_finalize (GObject *obj)
209 ModestMailOperationPrivate *priv;
211 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
216 g_error_free (priv->error);
220 g_object_unref (priv->source);
224 g_object_unref (priv->account);
225 priv->account = NULL;
229 G_OBJECT_CLASS(parent_class)->finalize (obj);
233 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
236 ModestMailOperation *obj;
237 ModestMailOperationPrivate *priv;
239 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
240 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
242 priv->op_type = op_type;
244 priv->source = g_object_ref(source);
250 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
252 ErrorCheckingUserCallback error_handler,
255 ModestMailOperation *obj;
256 ModestMailOperationPrivate *priv;
258 obj = modest_mail_operation_new (op_type, source);
259 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
261 g_return_val_if_fail (error_handler != NULL, obj);
262 priv->error_checking = error_handler;
268 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
270 ModestMailOperationPrivate *priv;
272 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
273 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
275 if (priv->error_checking != NULL)
276 priv->error_checking (self, priv->error_checking_user_data);
280 ModestMailOperationTypeOperation
281 modest_mail_operation_get_type_operation (ModestMailOperation *self)
283 ModestMailOperationPrivate *priv;
285 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
287 return priv->op_type;
291 modest_mail_operation_is_mine (ModestMailOperation *self,
294 ModestMailOperationPrivate *priv;
296 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
297 if (priv->source == NULL) return FALSE;
299 return priv->source == me;
303 modest_mail_operation_get_source (ModestMailOperation *self)
305 ModestMailOperationPrivate *priv;
307 g_return_val_if_fail (self, NULL);
309 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
311 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
315 return g_object_ref (priv->source);
318 ModestMailOperationStatus
319 modest_mail_operation_get_status (ModestMailOperation *self)
321 ModestMailOperationPrivate *priv;
323 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
324 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
325 MODEST_MAIL_OPERATION_STATUS_INVALID);
327 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
329 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
330 return MODEST_MAIL_OPERATION_STATUS_INVALID;
337 modest_mail_operation_get_error (ModestMailOperation *self)
339 ModestMailOperationPrivate *priv;
341 g_return_val_if_fail (self, NULL);
342 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
344 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
347 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
355 modest_mail_operation_cancel (ModestMailOperation *self)
357 ModestMailOperationPrivate *priv;
359 if (!MODEST_IS_MAIL_OPERATION (self)) {
360 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
364 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
366 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
373 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
375 /* This emits progress-changed on which the mail operation queue is
376 * listening, so the mail operation is correctly removed from the
377 * queue without further explicit calls. */
378 modest_mail_operation_notify_end (self);
384 modest_mail_operation_get_task_done (ModestMailOperation *self)
386 ModestMailOperationPrivate *priv;
388 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
390 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
395 modest_mail_operation_get_task_total (ModestMailOperation *self)
397 ModestMailOperationPrivate *priv;
399 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
401 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
406 modest_mail_operation_is_finished (ModestMailOperation *self)
408 ModestMailOperationPrivate *priv;
409 gboolean retval = FALSE;
411 if (!MODEST_IS_MAIL_OPERATION (self)) {
412 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
416 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
418 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
419 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
420 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
421 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
431 modest_mail_operation_get_id (ModestMailOperation *self)
433 ModestMailOperationPrivate *priv;
435 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
437 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
442 modest_mail_operation_set_id (ModestMailOperation *self,
445 ModestMailOperationPrivate *priv;
447 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
449 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
454 * Creates an image of the current state of a mail operation, the
455 * caller must free it
457 static ModestMailOperationState *
458 modest_mail_operation_clone_state (ModestMailOperation *self)
460 ModestMailOperationState *state;
461 ModestMailOperationPrivate *priv;
463 /* FIXME: this should be fixed properly
465 * in some cases, priv was NULL, so checking here to
468 g_return_val_if_fail (self, NULL);
469 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
470 g_return_val_if_fail (priv, NULL);
475 state = g_slice_new (ModestMailOperationState);
477 state->status = priv->status;
478 state->op_type = priv->op_type;
479 state->done = priv->done;
480 state->total = priv->total;
481 state->finished = modest_mail_operation_is_finished (self);
482 state->bytes_done = 0;
483 state->bytes_total = 0;
488 /* ******************************************************************* */
489 /* ************************** SEND ACTIONS ************************* */
490 /* ******************************************************************* */
493 modest_mail_operation_send_mail (ModestMailOperation *self,
494 TnyTransportAccount *transport_account,
497 TnySendQueue *send_queue = NULL;
498 ModestMailOperationPrivate *priv;
500 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
501 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
502 g_return_if_fail (TNY_IS_MSG (msg));
504 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
506 /* Get account and set it into mail_operation */
507 priv->account = g_object_ref (transport_account);
511 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
512 if (!TNY_IS_SEND_QUEUE(send_queue)) {
513 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
514 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
515 "modest: could not find send queue for account\n");
517 /* TODO: connect to the msg-sent in order to know when
518 the mail operation is finished */
519 tny_send_queue_add (send_queue, msg, &(priv->error));
520 /* TODO: we're setting always success, do the check in
522 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
525 /* TODO: do this in the handler of the "msg-sent"
526 signal.Notify about operation end */
527 modest_mail_operation_notify_end (self);
531 modest_mail_operation_send_new_mail (ModestMailOperation *self,
532 TnyTransportAccount *transport_account,
534 const gchar *from, const gchar *to,
535 const gchar *cc, const gchar *bcc,
536 const gchar *subject, const gchar *plain_body,
537 const gchar *html_body,
538 const GList *attachments_list,
539 TnyHeaderFlags priority_flags)
541 TnyMsg *new_msg = NULL;
542 TnyFolder *folder = NULL;
543 TnyHeader *header = NULL;
544 ModestMailOperationPrivate *priv = NULL;
546 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
547 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
549 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
551 /* Check parametters */
553 /* Set status failed and set an error */
554 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
555 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
556 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
557 _("Error trying to send a mail. You need to set at least one recipient"));
561 if (html_body == NULL) {
562 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
564 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
567 g_printerr ("modest: failed to create a new msg\n");
571 /* Set priority flags in message */
572 header = tny_msg_get_header (new_msg);
573 if (priority_flags != 0)
574 tny_header_set_flags (header, priority_flags);
575 if (attachments_list != NULL) {
576 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
578 g_object_unref (G_OBJECT(header));
580 /* Call mail operation */
581 modest_mail_operation_send_mail (self, transport_account, new_msg);
583 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
585 if (draft_msg != NULL) {
586 header = tny_msg_get_header (draft_msg);
587 /* Note: This can fail (with a warning) if the message is not really already in a folder,
588 * because this function requires it to have a UID. */
589 tny_folder_remove_msg (folder, header, NULL);
590 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
591 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
592 g_object_unref (header);
597 g_object_unref (G_OBJECT (new_msg));
601 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
602 TnyTransportAccount *transport_account,
604 const gchar *from, const gchar *to,
605 const gchar *cc, const gchar *bcc,
606 const gchar *subject, const gchar *plain_body,
607 const gchar *html_body,
608 const GList *attachments_list,
609 TnyHeaderFlags priority_flags)
612 TnyFolder *folder = NULL;
613 TnyHeader *header = NULL;
614 ModestMailOperationPrivate *priv = NULL;
616 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
617 g_return_val_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account), NULL);
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);
624 if (html_body == NULL) {
625 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
627 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
630 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
631 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
632 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
633 "modest: failed to create a new msg\n");
637 /* add priority flags */
638 header = tny_msg_get_header (msg);
639 tny_header_set_flags (header, priority_flags);
640 if (attachments_list != NULL)
641 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
642 g_object_unref (G_OBJECT(header));
644 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
646 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
647 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
648 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
649 "modest: failed to create a new msg\n");
653 if (draft_msg != NULL) {
654 header = tny_msg_get_header (draft_msg);
655 /* Remove the old draft expunging it */
656 tny_folder_remove_msg (folder, header, NULL);
657 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
658 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
659 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
660 g_object_unref (header);
664 tny_folder_add_msg (folder, msg, &(priv->error));
667 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
669 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
673 g_object_unref (G_OBJECT(folder));
675 modest_mail_operation_notify_end (self);
681 ModestMailOperation *mail_op;
682 TnyStoreAccount *account;
683 TnyTransportAccount *transport_account;
686 gchar *retrieve_type;
688 UpdateAccountCallback callback;
693 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
694 /* We use this folder observer to track the headers that have been
695 * added to a folder */
698 TnyList *new_headers;
699 } InternalFolderObserver;
703 } InternalFolderObserverClass;
705 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
707 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
708 internal_folder_observer,
710 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
714 foreach_add_item (gpointer header, gpointer user_data)
716 /* printf("DEBUG: %s: header subject=%s\n",
717 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
719 tny_list_prepend (TNY_LIST (user_data),
720 g_object_ref (G_OBJECT (header)));
723 /* This is the method that looks for new messages in a folder */
725 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
727 InternalFolderObserver *derived = (InternalFolderObserver *)self;
729 TnyFolderChangeChanged changed;
731 changed = tny_folder_change_get_changed (change);
733 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
736 /* Get added headers */
737 list = tny_simple_list_new ();
738 tny_folder_change_get_added_headers (change, list);
740 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
741 * __FUNCTION__, tny_list_get_length(list));
744 /* Add them to the folder observer */
745 tny_list_foreach (list, foreach_add_item,
746 derived->new_headers);
748 g_object_unref (G_OBJECT (list));
753 internal_folder_observer_init (InternalFolderObserver *self)
755 self->new_headers = tny_simple_list_new ();
758 internal_folder_observer_finalize (GObject *object)
760 InternalFolderObserver *self;
762 self = (InternalFolderObserver *) object;
763 g_object_unref (self->new_headers);
765 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
768 tny_folder_observer_init (TnyFolderObserverIface *iface)
770 iface->update_func = internal_folder_observer_update;
773 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
775 GObjectClass *object_class;
777 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
778 object_class = (GObjectClass*) klass;
779 object_class->finalize = internal_folder_observer_finalize;
785 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
788 TnyList *folders = tny_simple_list_new ();
790 tny_folder_store_get_folders (store, folders, query, NULL);
791 iter = tny_list_create_iterator (folders);
793 while (!tny_iterator_is_done (iter)) {
795 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
797 tny_list_prepend (all_folders, G_OBJECT (folder));
798 recurse_folders (folder, query, all_folders);
799 g_object_unref (G_OBJECT (folder));
801 tny_iterator_next (iter);
803 g_object_unref (G_OBJECT (iter));
804 g_object_unref (G_OBJECT (folders));
808 * Issues the "progress-changed" signal. The timer won't be removed,
809 * so you must call g_source_remove to stop the signal emission
812 idle_notify_progress (gpointer data)
814 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
815 ModestMailOperationState *state;
817 state = modest_mail_operation_clone_state (mail_op);
818 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
819 g_slice_free (ModestMailOperationState, state);
825 * Issues the "progress-changed" signal and removes the timer. It uses
826 * a lock to ensure that the progress information of the mail
827 * operation is not modified while there are notifications pending
830 idle_notify_progress_once (gpointer data)
834 pair = (ModestPair *) data;
836 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
838 /* Free the state and the reference to the mail operation */
839 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
840 g_object_unref (pair->first);
846 * Used by update_account_thread to notify the queue from the main
847 * loop. We call it inside an idle call to achieve that
850 idle_notify_update_account_queue (gpointer data)
852 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
853 ModestMailOperationPrivate *priv = NULL;
855 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
857 /* Do not need to block, the notify end will do it for us */
858 modest_mail_operation_notify_end (mail_op);
859 g_object_unref (mail_op);
865 compare_headers_by_date (gconstpointer a,
868 TnyHeader **header1, **header2;
871 header1 = (TnyHeader **) a;
872 header2 = (TnyHeader **) b;
874 sent1 = tny_header_get_date_sent (*header1);
875 sent2 = tny_header_get_date_sent (*header2);
877 /* We want the most recent ones (greater time_t) at the
886 set_last_updated_idle (gpointer data)
888 gdk_threads_enter ();
890 /* It does not matter if the time is not exactly the same than
891 the time when this idle was called, it's just an
892 approximation and it won't be very different */
893 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
895 MODEST_ACCOUNT_LAST_UPDATED,
899 gdk_threads_leave ();
905 idle_update_account_cb (gpointer data)
907 UpdateAccountInfo *idle_info;
909 idle_info = (UpdateAccountInfo *) data;
911 gdk_threads_enter ();
912 idle_info->callback (idle_info->mail_op,
913 idle_info->new_headers,
914 idle_info->user_data);
915 gdk_threads_leave ();
918 g_object_unref (idle_info->mail_op);
926 update_account_thread (gpointer thr_user_data)
928 static gboolean first_time = TRUE;
929 UpdateAccountInfo *info;
930 TnyList *all_folders = NULL;
931 GPtrArray *new_headers = NULL;
932 TnyIterator *iter = NULL;
933 TnyFolderStoreQuery *query = NULL;
934 ModestMailOperationPrivate *priv = NULL;
935 ModestTnySendQueue *send_queue = NULL;
937 info = (UpdateAccountInfo *) thr_user_data;
938 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
940 /* Get account and set it into mail_operation */
941 priv->account = g_object_ref (info->account);
944 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
945 * show any updates unless we do that
947 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
948 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
950 /* Get all the folders. We can do it synchronously because
951 we're already running in a different thread than the UI */
952 all_folders = tny_simple_list_new ();
953 query = tny_folder_store_query_new ();
954 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
955 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
960 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
964 iter = tny_list_create_iterator (all_folders);
965 while (!tny_iterator_is_done (iter)) {
966 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
968 recurse_folders (folder, query, all_folders);
969 tny_iterator_next (iter);
971 g_object_unref (G_OBJECT (iter));
973 /* Update status and notify. We need to call the notification
974 with a source function in order to call it from the main
975 loop. We need that in order not to get into trouble with
976 Gtk+. We use a timeout in order to provide more status
977 information, because the sync tinymail call does not
978 provide it for the moment */
979 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
981 /* Refresh folders */
982 new_headers = g_ptr_array_new ();
983 iter = tny_list_create_iterator (all_folders);
985 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
987 InternalFolderObserver *observer;
988 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
990 /* Refresh the folder */
991 /* Our observer receives notification of new emails during folder refreshes,
992 * so we can use observer->new_headers.
994 observer = g_object_new (internal_folder_observer_get_type (), NULL);
995 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
997 /* This gets the status information (headers) from the server.
998 * We use the blocking version, because we are already in a separate
1002 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1003 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1006 /* If the retrieve type is full messages, refresh and get the messages */
1007 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1009 iter = tny_list_create_iterator (observer->new_headers);
1010 while (!tny_iterator_is_done (iter)) {
1011 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1013 /* Apply per-message size limits */
1014 if (tny_header_get_message_size (header) < info->max_size)
1015 g_ptr_array_add (new_headers, g_object_ref (header));
1017 g_object_unref (header);
1018 tny_iterator_next (iter);
1020 g_object_unref (iter);
1022 /* We do not need to do it the first time
1023 because it's automatically done by the tree
1025 if (G_UNLIKELY (!first_time))
1026 tny_folder_poke_status (TNY_FOLDER (folder));
1028 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1029 g_object_unref (observer);
1032 g_object_unref (G_OBJECT (folder));
1035 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1039 tny_iterator_next (iter);
1042 did_a_cancel = FALSE;
1044 g_object_unref (G_OBJECT (iter));
1045 g_source_remove (timeout);
1047 if (new_headers->len > 0) {
1051 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1053 /* Apply message count limit */
1054 /* If the number of messages exceeds the maximum, ask the
1055 * user to download them all,
1056 * as per the UI spec "Retrieval Limits" section in 4.4:
1058 if (new_headers->len > info->retrieve_limit) {
1059 /* TODO: Ask the user, instead of just
1061 * mail_nc_msg_count_limit_exceeded, with 'Get
1062 * all' and 'Newest only' buttons. */
1063 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1064 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1065 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1066 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1067 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1072 priv->total = MIN (new_headers->len, info->retrieve_limit);
1073 while (msg_num < priv->total) {
1075 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1076 TnyFolder *folder = tny_header_get_folder (header);
1077 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1078 ModestMailOperationState *state;
1082 /* We can not just use the mail operation because the
1083 values of done and total could change before the
1085 state = modest_mail_operation_clone_state (info->mail_op);
1086 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1087 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1088 pair, (GDestroyNotify) modest_pair_free);
1090 g_object_unref (msg);
1091 g_object_unref (folder);
1095 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1096 g_ptr_array_free (new_headers, FALSE);
1099 /* Perform send (if operation was not cancelled) */
1100 if (did_a_cancel) goto out;
1101 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1104 if (priv->account != NULL)
1105 g_object_unref (priv->account);
1106 priv->account = g_object_ref (info->transport_account);
1108 send_queue = modest_runtime_get_send_queue (info->transport_account);
1110 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1111 modest_tny_send_queue_try_to_send (send_queue);
1112 /* g_source_remove (timeout); */
1114 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1115 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1116 "cannot create a send queue for %s\n",
1117 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1118 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1121 /* Check if the operation was a success */
1123 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1125 /* Update the last updated key */
1126 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1127 set_last_updated_idle,
1128 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1129 (GDestroyNotify) g_free);
1134 if (info->callback) {
1135 UpdateAccountInfo *idle_info;
1137 /* This thread is not in the main lock */
1138 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1139 idle_info->mail_op = g_object_ref (info->mail_op);
1140 idle_info->new_headers = (new_headers) ? new_headers->len : 0;
1141 idle_info->callback = info->callback;
1142 g_idle_add (idle_update_account_cb, idle_info);
1145 /* Notify about operation end. Note that the info could be
1146 freed before this idle happens, but the mail operation will
1148 g_idle_add (idle_notify_update_account_queue, g_object_ref (info->mail_op));
1151 g_object_unref (query);
1152 g_object_unref (all_folders);
1153 g_object_unref (info->account);
1154 g_object_unref (info->transport_account);
1155 g_free (info->retrieve_type);
1156 g_slice_free (UpdateAccountInfo, info);
1164 modest_mail_operation_update_account (ModestMailOperation *self,
1165 const gchar *account_name,
1166 UpdateAccountCallback callback,
1170 UpdateAccountInfo *info;
1171 ModestMailOperationPrivate *priv;
1172 ModestAccountMgr *mgr;
1173 TnyStoreAccount *modest_account;
1174 TnyTransportAccount *transport_account;
1176 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1177 g_return_val_if_fail (account_name, FALSE);
1179 /* Init mail operation. Set total and done to 0, and do not
1180 update them, this way the progress objects will know that
1181 we have no clue about the number of the objects */
1182 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1185 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1187 /* Make sure that we have a connection, and request one
1189 * TODO: Is there some way to trigger this for every attempt to
1190 * use the network? */
1191 if (!modest_platform_connect_and_wait (NULL))
1194 /* Get the Modest account */
1195 modest_account = (TnyStoreAccount *)
1196 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1198 TNY_ACCOUNT_TYPE_STORE);
1200 if (!modest_account) {
1201 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1202 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1203 "cannot get tny store account for %s\n", account_name);
1208 /* Get the transport account, we can not do it in the thread
1209 due to some problems with dbus */
1210 transport_account = (TnyTransportAccount *)
1211 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1213 if (!transport_account) {
1214 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1215 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1216 "cannot get tny transport account for %s\n", account_name);
1220 /* Create the helper object */
1221 info = g_slice_new (UpdateAccountInfo);
1222 info->mail_op = self;
1223 info->account = modest_account;
1224 info->transport_account = transport_account;
1225 info->callback = callback;
1226 info->user_data = user_data;
1228 /* Get the message size limit */
1229 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1230 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1231 if (info->max_size == 0)
1232 info->max_size = G_MAXINT;
1234 info->max_size = info->max_size * KB;
1236 /* Get per-account retrieval type */
1237 mgr = modest_runtime_get_account_mgr ();
1238 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1239 MODEST_ACCOUNT_RETRIEVE, FALSE);
1241 /* Get per-account message amount retrieval limit */
1242 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1243 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1244 if (info->retrieve_limit == 0)
1245 info->retrieve_limit = G_MAXINT;
1247 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1249 /* Set account busy */
1250 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1251 priv->account_name = g_strdup(account_name);
1253 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1258 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1260 callback (self, 0, user_data);
1261 modest_mail_operation_notify_end (self);
1265 /* ******************************************************************* */
1266 /* ************************** STORE ACTIONS ************************* */
1267 /* ******************************************************************* */
1271 modest_mail_operation_create_folder (ModestMailOperation *self,
1272 TnyFolderStore *parent,
1275 ModestMailOperationPrivate *priv;
1276 TnyFolder *new_folder = NULL;
1278 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1279 g_return_val_if_fail (name, NULL);
1281 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1284 if (TNY_IS_FOLDER (parent)) {
1285 /* Check folder rules */
1286 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1287 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1288 /* Set status failed and set an error */
1289 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1290 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1291 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1292 _("mail_in_ui_folder_create_error"));
1296 if (!strcmp (name, " ") || strchr (name, '/')) {
1297 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1298 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1299 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1300 _("mail_in_ui_folder_create_error"));
1304 /* Create the folder */
1305 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1306 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1308 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1311 /* Notify about operation end */
1312 modest_mail_operation_notify_end (self);
1318 modest_mail_operation_remove_folder (ModestMailOperation *self,
1320 gboolean remove_to_trash)
1322 TnyAccount *account;
1323 ModestMailOperationPrivate *priv;
1324 ModestTnyFolderRules rules;
1326 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1327 g_return_if_fail (TNY_IS_FOLDER (folder));
1329 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1331 /* Check folder rules */
1332 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1333 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1334 /* Set status failed and set an error */
1335 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1336 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1337 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1338 _("mail_in_ui_folder_delete_error"));
1342 /* Get the account */
1343 account = modest_tny_folder_get_account (folder);
1344 priv->account = g_object_ref(account);
1346 /* Delete folder or move to trash */
1347 if (remove_to_trash) {
1348 TnyFolder *trash_folder = NULL;
1349 trash_folder = modest_tny_account_get_special_folder (account,
1350 TNY_FOLDER_TYPE_TRASH);
1351 /* TODO: error_handling */
1352 modest_mail_operation_xfer_folder (self, folder,
1353 TNY_FOLDER_STORE (trash_folder),
1356 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1358 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1359 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1362 g_object_unref (G_OBJECT (parent));
1364 g_object_unref (G_OBJECT (account));
1367 /* Notify about operation end */
1368 modest_mail_operation_notify_end (self);
1372 transfer_folder_status_cb (GObject *obj,
1376 ModestMailOperation *self;
1377 ModestMailOperationPrivate *priv;
1378 ModestMailOperationState *state;
1379 XFerMsgAsyncHelper *helper;
1381 g_return_if_fail (status != NULL);
1382 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1384 helper = (XFerMsgAsyncHelper *) user_data;
1385 g_return_if_fail (helper != NULL);
1387 self = helper->mail_op;
1388 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1390 priv->done = status->position;
1391 priv->total = status->of_total;
1393 state = modest_mail_operation_clone_state (self);
1394 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1395 g_slice_free (ModestMailOperationState, state);
1400 transfer_folder_cb (TnyFolder *folder,
1401 TnyFolderStore *into,
1403 TnyFolder *new_folder,
1407 XFerMsgAsyncHelper *helper;
1408 ModestMailOperation *self = NULL;
1409 ModestMailOperationPrivate *priv = NULL;
1411 helper = (XFerMsgAsyncHelper *) user_data;
1412 g_return_if_fail (helper != NULL);
1414 self = helper->mail_op;
1415 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1418 priv->error = g_error_copy (*err);
1420 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1421 } else if (cancelled) {
1422 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1423 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1424 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1425 _("Transference of %s was cancelled."),
1426 tny_folder_get_name (folder));
1429 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1432 /* Notify about operation end */
1433 modest_mail_operation_notify_end (self);
1435 /* If user defined callback function was defined, call it */
1436 if (helper->user_callback) {
1437 gdk_threads_enter ();
1438 helper->user_callback (priv->source, helper->user_data);
1439 gdk_threads_leave ();
1443 g_object_unref (helper->mail_op);
1444 g_slice_free (XFerMsgAsyncHelper, helper);
1445 g_object_unref (folder);
1446 g_object_unref (into);
1450 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1452 TnyFolderStore *parent,
1453 gboolean delete_original,
1454 XferMsgsAsynUserCallback user_callback,
1457 ModestMailOperationPrivate *priv = NULL;
1458 ModestTnyFolderRules parent_rules = 0, rules;
1459 XFerMsgAsyncHelper *helper = NULL;
1461 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1462 g_return_if_fail (TNY_IS_FOLDER (folder));
1464 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1466 /* Get account and set it into mail_operation */
1467 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1468 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1470 /* Get folder rules */
1471 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1472 if (TNY_IS_FOLDER (parent))
1473 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1475 /* The moveable restriction is applied also to copy operation */
1476 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1477 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1478 /* Set status failed and set an error */
1479 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1480 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1481 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1482 _("mail_in_ui_folder_move_target_error"));
1484 /* Notify the queue */
1485 modest_mail_operation_notify_end (self);
1486 } else if (TNY_IS_FOLDER (parent) &&
1487 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1488 /* Set status failed and set an error */
1489 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1490 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1491 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1492 _("FIXME: parent folder does not accept new folders"));
1494 /* Notify the queue */
1495 modest_mail_operation_notify_end (self);
1497 /* Pick references for async calls */
1498 g_object_ref (folder);
1499 g_object_ref (parent);
1501 /* Create the helper */
1502 helper = g_slice_new0 (XFerMsgAsyncHelper);
1503 helper->mail_op = g_object_ref(self);
1504 helper->dest_folder = NULL;
1505 helper->headers = NULL;
1506 helper->user_callback = user_callback;
1507 helper->user_data = user_data;
1509 /* Move/Copy folder */
1510 tny_folder_copy_async (folder,
1512 tny_folder_get_name (folder),
1515 transfer_folder_status_cb,
1522 modest_mail_operation_rename_folder (ModestMailOperation *self,
1526 ModestMailOperationPrivate *priv;
1527 ModestTnyFolderRules rules;
1528 XFerMsgAsyncHelper *helper;
1530 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1531 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1532 g_return_if_fail (name);
1534 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1536 /* Get account and set it into mail_operation */
1537 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1539 /* Check folder rules */
1540 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1541 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1542 /* Set status failed and set an error */
1543 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1544 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1545 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1546 _("FIXME: unable to rename"));
1548 /* Notify about operation end */
1549 modest_mail_operation_notify_end (self);
1550 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1551 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1552 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1553 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1554 _("FIXME: unable to rename"));
1555 /* Notify about operation end */
1556 modest_mail_operation_notify_end (self);
1558 TnyFolderStore *into;
1560 /* Create the helper */
1561 helper = g_slice_new0 (XFerMsgAsyncHelper);
1562 helper->mail_op = g_object_ref(self);
1563 helper->dest_folder = NULL;
1564 helper->headers = NULL;
1565 helper->user_callback = NULL;
1566 helper->user_data = NULL;
1568 /* Rename. Camel handles folder subscription/unsubscription */
1569 into = tny_folder_get_folder_store (folder);
1570 tny_folder_copy_async (folder, into, name, TRUE,
1572 transfer_folder_status_cb,
1576 g_object_unref (into);
1580 /* ******************************************************************* */
1581 /* ************************** MSG ACTIONS ************************* */
1582 /* ******************************************************************* */
1584 void modest_mail_operation_get_msg (ModestMailOperation *self,
1586 GetMsgAsyncUserCallback user_callback,
1589 GetMsgAsyncHelper *helper = NULL;
1591 ModestMailOperationPrivate *priv;
1593 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1594 g_return_if_fail (TNY_IS_HEADER (header));
1596 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1597 folder = tny_header_get_folder (header);
1599 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1601 /* Get message from folder */
1603 /* Get account and set it into mail_operation */
1604 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1606 helper = g_slice_new0 (GetMsgAsyncHelper);
1607 helper->mail_op = self;
1608 helper->user_callback = user_callback;
1609 helper->user_data = user_data;
1610 helper->header = g_object_ref (header);
1612 // The callback's reference so that the mail op is not
1613 // finalized until the async operation is completed even if
1614 // the user canceled the request meanwhile.
1615 g_object_ref (G_OBJECT (helper->mail_op));
1617 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1619 g_object_unref (G_OBJECT (folder));
1621 /* Set status failed and set an error */
1622 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1623 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1624 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1625 _("Error trying to get a message. No folder found for header"));
1627 /* Notify the queue */
1628 modest_mail_operation_notify_end (self);
1633 get_msg_cb (TnyFolder *folder,
1639 GetMsgAsyncHelper *helper = NULL;
1640 ModestMailOperation *self = NULL;
1641 ModestMailOperationPrivate *priv = NULL;
1643 helper = (GetMsgAsyncHelper *) user_data;
1644 g_return_if_fail (helper != NULL);
1645 self = helper->mail_op;
1646 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1647 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1649 /* Check errors and cancel */
1651 priv->error = g_error_copy (*error);
1652 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1653 } else if (cancelled) {
1654 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1655 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1656 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1657 _("Error trying to refresh the contents of %s"),
1658 tny_folder_get_name (folder));
1660 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1663 /* If user defined callback function was defined, call it even
1664 if the operation failed*/
1665 if (helper->user_callback) {
1666 /* This callback is called into an iddle by tinymail,
1667 and idles are not in the main lock */
1668 gdk_threads_enter ();
1669 helper->user_callback (self, helper->header, msg, helper->user_data);
1670 gdk_threads_leave ();
1674 g_object_unref (helper->mail_op);
1675 g_object_unref (helper->header);
1676 g_slice_free (GetMsgAsyncHelper, helper);
1678 /* Notify about operation end */
1679 modest_mail_operation_notify_end (self);
1683 get_msg_status_cb (GObject *obj,
1687 GetMsgAsyncHelper *helper = NULL;
1688 ModestMailOperation *self;
1689 ModestMailOperationPrivate *priv;
1690 ModestMailOperationState *state;
1692 g_return_if_fail (status != NULL);
1693 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1695 helper = (GetMsgAsyncHelper *) user_data;
1696 g_return_if_fail (helper != NULL);
1698 self = helper->mail_op;
1699 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1701 if(priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1707 state = modest_mail_operation_clone_state (self);
1708 state->bytes_done = status->position;
1709 state->bytes_total = status->of_total;
1710 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1711 g_slice_free (ModestMailOperationState, state);
1714 /****************************************************/
1716 ModestMailOperation *mail_op;
1718 GetMsgAsyncUserCallback user_callback;
1720 GDestroyNotify notify;
1724 GetMsgAsyncUserCallback user_callback;
1728 ModestMailOperation *mail_op;
1729 } NotifyGetMsgsInfo;
1733 * Used by get_msgs_full_thread to call the user_callback for each
1734 * message that has been read
1737 notify_get_msgs_full (gpointer data)
1739 NotifyGetMsgsInfo *info;
1741 info = (NotifyGetMsgsInfo *) data;
1743 /* Call the user callback. Idles are not in the main lock, so
1745 gdk_threads_enter ();
1746 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1747 gdk_threads_leave ();
1749 g_slice_free (NotifyGetMsgsInfo, info);
1755 * Used by get_msgs_full_thread to free al the thread resources and to
1756 * call the destroy function for the passed user_data
1759 get_msgs_full_destroyer (gpointer data)
1761 GetFullMsgsInfo *info;
1763 info = (GetFullMsgsInfo *) data;
1766 gdk_threads_enter ();
1767 info->notify (info->user_data);
1768 gdk_threads_leave ();
1772 g_object_unref (info->headers);
1773 g_slice_free (GetFullMsgsInfo, info);
1779 get_msgs_full_thread (gpointer thr_user_data)
1781 GetFullMsgsInfo *info;
1782 ModestMailOperationPrivate *priv = NULL;
1783 TnyIterator *iter = NULL;
1785 info = (GetFullMsgsInfo *) thr_user_data;
1786 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1788 iter = tny_list_create_iterator (info->headers);
1789 while (!tny_iterator_is_done (iter)) {
1793 header = TNY_HEADER (tny_iterator_get_current (iter));
1794 folder = tny_header_get_folder (header);
1796 /* Get message from folder */
1799 /* The callback will call it per each header */
1800 msg = tny_folder_get_msg (folder, header, &(priv->error));
1803 ModestMailOperationState *state;
1808 /* notify progress */
1809 state = modest_mail_operation_clone_state (info->mail_op);
1810 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1811 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1812 pair, (GDestroyNotify) modest_pair_free);
1814 /* The callback is the responsible for
1815 freeing the message */
1816 if (info->user_callback) {
1817 NotifyGetMsgsInfo *info_notify;
1818 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1819 info_notify->user_callback = info->user_callback;
1820 info_notify->mail_op = info->mail_op;
1821 info_notify->header = g_object_ref (header);
1822 info_notify->msg = g_object_ref (msg);
1823 info_notify->user_data = info->user_data;
1824 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1825 notify_get_msgs_full,
1828 g_object_unref (msg);
1831 /* Set status failed and set an error */
1832 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1833 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1834 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1835 "Error trying to get a message. No folder found for header");
1837 g_object_unref (header);
1838 tny_iterator_next (iter);
1841 /* Set operation status */
1842 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1843 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1845 /* Notify about operation end */
1846 g_idle_add (idle_notify_update_account_queue, g_object_ref (info->mail_op));
1848 /* Free thread resources. Will be called after all previous idles */
1849 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1855 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1856 TnyList *header_list,
1857 GetMsgAsyncUserCallback user_callback,
1859 GDestroyNotify notify)
1861 TnyHeader *header = NULL;
1862 TnyFolder *folder = NULL;
1864 ModestMailOperationPrivate *priv = NULL;
1865 GetFullMsgsInfo *info = NULL;
1866 gboolean size_ok = TRUE;
1868 TnyIterator *iter = NULL;
1870 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1872 /* Init mail operation */
1873 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1874 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1876 priv->total = tny_list_get_length(header_list);
1878 /* Get account and set it into mail_operation */
1879 if (tny_list_get_length (header_list) >= 1) {
1880 iter = tny_list_create_iterator (header_list);
1881 header = TNY_HEADER (tny_iterator_get_current (iter));
1882 folder = tny_header_get_folder (header);
1883 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1884 g_object_unref (header);
1885 g_object_unref (folder);
1887 if (tny_list_get_length (header_list) == 1) {
1888 g_object_unref (iter);
1893 /* Get msg size limit */
1894 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1895 MODEST_CONF_MSG_SIZE_LIMIT,
1898 g_clear_error (&(priv->error));
1899 max_size = G_MAXINT;
1901 max_size = max_size * KB;
1904 /* Check message size limits. If there is only one message
1905 always retrieve it */
1907 while (!tny_iterator_is_done (iter) && size_ok) {
1908 header = TNY_HEADER (tny_iterator_get_current (iter));
1909 if (tny_header_get_message_size (header) >= max_size)
1911 g_object_unref (header);
1912 tny_iterator_next (iter);
1914 g_object_unref (iter);
1918 /* Create the info */
1919 info = g_slice_new0 (GetFullMsgsInfo);
1920 info->mail_op = self;
1921 info->user_callback = user_callback;
1922 info->user_data = user_data;
1923 info->headers = g_object_ref (header_list);
1924 info->notify = notify;
1926 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1928 /* Set status failed and set an error */
1929 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1930 /* FIXME: the error msg is different for pop */
1931 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1932 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1933 _("emev_ni_ui_imap_msg_size_exceed_error"));
1934 /* Remove from queue and free resources */
1935 modest_mail_operation_notify_end (self);
1943 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
1944 gboolean remove_to_trash /*ignored*/)
1947 ModestMailOperationPrivate *priv;
1949 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1950 g_return_if_fail (TNY_IS_HEADER (header));
1952 if (remove_to_trash)
1953 g_warning ("remove to trash is not implemented");
1955 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1956 folder = tny_header_get_folder (header);
1958 /* Get account and set it into mail_operation */
1959 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1961 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1964 tny_folder_remove_msg (folder, header, &(priv->error));
1966 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
1967 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
1969 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
1970 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
1971 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
1972 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
1975 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
1981 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1983 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1986 g_object_unref (G_OBJECT (folder));
1988 /* Notify about operation end */
1989 modest_mail_operation_notify_end (self);
1993 transfer_msgs_status_cb (GObject *obj,
1997 XFerMsgAsyncHelper *helper = NULL;
1998 ModestMailOperation *self;
1999 ModestMailOperationPrivate *priv;
2000 ModestMailOperationState *state;
2003 g_return_if_fail (status != NULL);
2004 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2006 helper = (XFerMsgAsyncHelper *) user_data;
2007 g_return_if_fail (helper != NULL);
2009 self = helper->mail_op;
2010 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2012 priv->done = status->position;
2013 priv->total = status->of_total;
2015 state = modest_mail_operation_clone_state (self);
2016 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2017 g_slice_free (ModestMailOperationState, state);
2022 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2024 XFerMsgAsyncHelper *helper;
2025 ModestMailOperation *self;
2026 ModestMailOperationPrivate *priv;
2028 helper = (XFerMsgAsyncHelper *) user_data;
2029 self = helper->mail_op;
2031 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2034 priv->error = g_error_copy (*err);
2036 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2037 } else if (cancelled) {
2038 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2039 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2040 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2041 _("Error trying to refresh the contents of %s"),
2042 tny_folder_get_name (folder));
2045 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2048 /* Notify about operation end */
2049 modest_mail_operation_notify_end (self);
2051 /* If user defined callback function was defined, call it */
2052 if (helper->user_callback) {
2053 gdk_threads_enter ();
2054 helper->user_callback (priv->source, helper->user_data);
2055 gdk_threads_leave ();
2059 g_object_unref (helper->headers);
2060 g_object_unref (helper->dest_folder);
2061 g_object_unref (helper->mail_op);
2062 g_slice_free (XFerMsgAsyncHelper, helper);
2063 g_object_unref (folder);
2068 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2071 gboolean delete_original,
2072 XferMsgsAsynUserCallback user_callback,
2075 ModestMailOperationPrivate *priv;
2077 TnyFolder *src_folder;
2078 XFerMsgAsyncHelper *helper;
2080 ModestTnyFolderRules rules;
2081 const gchar *id1 = NULL;
2082 const gchar *id2 = NULL;
2083 gboolean same_folder = FALSE;
2085 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2086 g_return_if_fail (TNY_IS_LIST (headers));
2087 g_return_if_fail (TNY_IS_FOLDER (folder));
2089 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2092 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2094 /* Apply folder rules */
2095 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2096 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2097 /* Set status failed and set an error */
2098 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2099 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2100 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2101 _("ckct_ib_unable_to_paste_here"));
2102 /* Notify the queue */
2103 modest_mail_operation_notify_end (self);
2107 /* Get source folder */
2108 iter = tny_list_create_iterator (headers);
2109 header = TNY_HEADER (tny_iterator_get_current (iter));
2110 src_folder = tny_header_get_folder (header);
2111 g_object_unref (header);
2112 g_object_unref (iter);
2114 /* Check folder source and destination */
2115 id1 = tny_folder_get_id (src_folder);
2116 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2117 same_folder = !g_ascii_strcasecmp (id1, id2);
2119 /* Set status failed and set an error */
2120 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2121 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2122 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2123 _("mcen_ib_unable_to_copy_samefolder"));
2125 /* Notify the queue */
2126 modest_mail_operation_notify_end (self);
2129 g_object_unref (src_folder);
2133 /* Create the helper */
2134 helper = g_slice_new0 (XFerMsgAsyncHelper);
2135 helper->mail_op = g_object_ref(self);
2136 helper->dest_folder = g_object_ref(folder);
2137 helper->headers = g_object_ref(headers);
2138 helper->user_callback = user_callback;
2139 helper->user_data = user_data;
2141 /* Get account and set it into mail_operation */
2142 priv->account = modest_tny_folder_get_account (src_folder);
2144 /* Transfer messages */
2145 tny_folder_transfer_msgs_async (src_folder,
2150 transfer_msgs_status_cb,
2156 on_refresh_folder (TnyFolder *folder,
2161 RefreshAsyncHelper *helper = NULL;
2162 ModestMailOperation *self = NULL;
2163 ModestMailOperationPrivate *priv = NULL;
2165 helper = (RefreshAsyncHelper *) user_data;
2166 self = helper->mail_op;
2167 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2170 priv->error = g_error_copy (*error);
2171 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2176 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2177 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2178 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2179 _("Error trying to refresh the contents of %s"),
2180 tny_folder_get_name (folder));
2184 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2186 /* Call user defined callback, if it exists */
2187 if (helper->user_callback) {
2188 gdk_threads_enter ();
2189 helper->user_callback (self, folder, helper->user_data);
2190 gdk_threads_leave ();
2194 g_object_unref (helper->mail_op);
2195 g_slice_free (RefreshAsyncHelper, helper);
2196 g_object_unref (folder);
2198 /* Notify about operation end */
2199 modest_mail_operation_notify_end (self);
2203 on_refresh_folder_status_update (GObject *obj,
2207 RefreshAsyncHelper *helper = NULL;
2208 ModestMailOperation *self = NULL;
2209 ModestMailOperationPrivate *priv = NULL;
2210 ModestMailOperationState *state;
2212 g_return_if_fail (user_data != NULL);
2213 g_return_if_fail (status != NULL);
2214 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2216 helper = (RefreshAsyncHelper *) user_data;
2217 self = helper->mail_op;
2218 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2220 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2222 priv->done = status->position;
2223 priv->total = status->of_total;
2225 state = modest_mail_operation_clone_state (self);
2226 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2227 g_slice_free (ModestMailOperationState, state);
2231 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2233 RefreshAsyncUserCallback user_callback,
2236 ModestMailOperationPrivate *priv = NULL;
2237 RefreshAsyncHelper *helper = NULL;
2239 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2241 /* Pick a reference */
2242 g_object_ref (folder);
2244 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2246 /* Get account and set it into mail_operation */
2247 priv->account = modest_tny_folder_get_account (folder);
2249 /* Create the helper */
2250 helper = g_slice_new0 (RefreshAsyncHelper);
2251 helper->mail_op = g_object_ref(self);
2252 helper->user_callback = user_callback;
2253 helper->user_data = user_data;
2255 /* Refresh the folder. TODO: tinymail could issue a status
2256 updates before the callback call then this could happen. We
2257 must review the design */
2258 tny_folder_refresh_async (folder,
2260 on_refresh_folder_status_update,
2266 * It's used by the mail operation queue to notify the observers
2267 * attached to that signal that the operation finished. We need to use
2268 * that because tinymail does not give us the progress of a given
2269 * operation when it finishes (it directly calls the operation
2273 modest_mail_operation_notify_end (ModestMailOperation *self)
2275 ModestMailOperationState *state;
2276 ModestMailOperationPrivate *priv = NULL;
2278 g_return_if_fail (self);
2280 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2282 /* Set the account back to not busy */
2283 if (priv->account_name) {
2284 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2285 priv->account_name, FALSE);
2286 g_free(priv->account_name);
2287 priv->account_name = NULL;
2290 /* Notify the observers about the mail opertation end */
2291 state = modest_mail_operation_clone_state (self);
2292 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2293 g_slice_free (ModestMailOperationState, state);