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 g_object_unref (G_OBJECT(header));
577 /* Call mail operation */
578 modest_mail_operation_send_mail (self, transport_account, new_msg);
580 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
582 if (draft_msg != NULL) {
583 header = tny_msg_get_header (draft_msg);
584 /* Note: This can fail (with a warning) if the message is not really already in a folder,
585 * because this function requires it to have a UID. */
586 tny_folder_remove_msg (folder, header, NULL);
587 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
588 g_object_unref (header);
593 g_object_unref (G_OBJECT (new_msg));
597 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
598 TnyTransportAccount *transport_account,
600 const gchar *from, const gchar *to,
601 const gchar *cc, const gchar *bcc,
602 const gchar *subject, const gchar *plain_body,
603 const gchar *html_body,
604 const GList *attachments_list,
605 TnyHeaderFlags priority_flags)
608 TnyFolder *folder = NULL;
609 TnyHeader *header = NULL;
610 ModestMailOperationPrivate *priv = NULL;
612 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
613 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
615 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
617 /* Get account and set it into mail_operation */
618 priv->account = g_object_ref (transport_account);
620 if (html_body == NULL) {
621 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
623 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
626 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
627 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
628 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
629 "modest: failed to create a new msg\n");
633 /* add priority flags */
634 header = tny_msg_get_header (msg);
635 tny_header_set_flags (header, priority_flags);
636 g_object_unref (G_OBJECT(header));
638 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
640 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
641 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
642 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
643 "modest: failed to create a new msg\n");
647 if (draft_msg != NULL) {
648 header = tny_msg_get_header (draft_msg);
649 /* Remove the old draft expunging it */
650 tny_folder_remove_msg (folder, header, NULL);
651 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
652 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
653 g_object_unref (header);
657 tny_folder_add_msg (folder, msg, &(priv->error));
660 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
662 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
666 g_object_unref (G_OBJECT(msg));
668 g_object_unref (G_OBJECT(folder));
670 modest_mail_operation_notify_end (self);
675 ModestMailOperation *mail_op;
676 TnyStoreAccount *account;
677 TnyTransportAccount *transport_account;
680 gchar *retrieve_type;
682 UpdateAccountCallback callback;
687 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
688 /* We use this folder observer to track the headers that have been
689 * added to a folder */
692 TnyList *new_headers;
693 } InternalFolderObserver;
697 } InternalFolderObserverClass;
699 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
701 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
702 internal_folder_observer,
704 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
708 foreach_add_item (gpointer header, gpointer user_data)
710 /* printf("DEBUG: %s: header subject=%s\n",
711 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
713 tny_list_prepend (TNY_LIST (user_data),
714 g_object_ref (G_OBJECT (header)));
717 /* This is the method that looks for new messages in a folder */
719 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
721 InternalFolderObserver *derived = (InternalFolderObserver *)self;
723 TnyFolderChangeChanged changed;
725 changed = tny_folder_change_get_changed (change);
727 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
730 /* Get added headers */
731 list = tny_simple_list_new ();
732 tny_folder_change_get_added_headers (change, list);
734 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
735 * __FUNCTION__, tny_list_get_length(list));
738 /* Add them to the folder observer */
739 tny_list_foreach (list, foreach_add_item,
740 derived->new_headers);
742 g_object_unref (G_OBJECT (list));
747 internal_folder_observer_init (InternalFolderObserver *self)
749 self->new_headers = tny_simple_list_new ();
752 internal_folder_observer_finalize (GObject *object)
754 InternalFolderObserver *self;
756 self = (InternalFolderObserver *) object;
757 g_object_unref (self->new_headers);
759 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
762 tny_folder_observer_init (TnyFolderObserverIface *iface)
764 iface->update_func = internal_folder_observer_update;
767 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
769 GObjectClass *object_class;
771 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
772 object_class = (GObjectClass*) klass;
773 object_class->finalize = internal_folder_observer_finalize;
779 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
782 TnyList *folders = tny_simple_list_new ();
784 tny_folder_store_get_folders (store, folders, query, NULL);
785 iter = tny_list_create_iterator (folders);
787 while (!tny_iterator_is_done (iter)) {
789 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
791 tny_list_prepend (all_folders, G_OBJECT (folder));
792 recurse_folders (folder, query, all_folders);
793 g_object_unref (G_OBJECT (folder));
795 tny_iterator_next (iter);
797 g_object_unref (G_OBJECT (iter));
798 g_object_unref (G_OBJECT (folders));
802 * Issues the "progress-changed" signal. The timer won't be removed,
803 * so you must call g_source_remove to stop the signal emission
806 idle_notify_progress (gpointer data)
808 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
809 ModestMailOperationState *state;
811 state = modest_mail_operation_clone_state (mail_op);
812 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
813 g_slice_free (ModestMailOperationState, state);
819 * Issues the "progress-changed" signal and removes the timer. It uses
820 * a lock to ensure that the progress information of the mail
821 * operation is not modified while there are notifications pending
824 idle_notify_progress_once (gpointer data)
828 pair = (ModestPair *) data;
830 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
832 /* Free the state and the reference to the mail operation */
833 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
834 g_object_unref (pair->first);
840 * Used by update_account_thread to notify the queue from the main
841 * loop. We call it inside an idle call to achieve that
844 idle_notify_update_account_queue (gpointer data)
846 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
847 ModestMailOperationPrivate *priv = NULL;
849 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
851 /* Do not need to block, the notify end will do it for us */
852 modest_mail_operation_notify_end (mail_op);
853 g_object_unref (mail_op);
859 compare_headers_by_date (gconstpointer a,
862 TnyHeader **header1, **header2;
865 header1 = (TnyHeader **) a;
866 header2 = (TnyHeader **) b;
868 sent1 = tny_header_get_date_sent (*header1);
869 sent2 = tny_header_get_date_sent (*header2);
871 /* We want the most recent ones (greater time_t) at the
880 set_last_updated_idle (gpointer data)
882 gdk_threads_enter ();
884 /* It does not matter if the time is not exactly the same than
885 the time when this idle was called, it's just an
886 approximation and it won't be very different */
887 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
889 MODEST_ACCOUNT_LAST_UPDATED,
893 gdk_threads_leave ();
899 idle_update_account_cb (gpointer data)
901 UpdateAccountInfo *idle_info;
903 idle_info = (UpdateAccountInfo *) data;
905 gdk_threads_enter ();
906 idle_info->callback (idle_info->mail_op,
907 idle_info->new_headers,
908 idle_info->user_data);
909 gdk_threads_leave ();
912 g_object_unref (idle_info->mail_op);
920 update_account_thread (gpointer thr_user_data)
922 static gboolean first_time = TRUE;
923 UpdateAccountInfo *info;
924 TnyList *all_folders = NULL;
925 GPtrArray *new_headers = NULL;
926 TnyIterator *iter = NULL;
927 TnyFolderStoreQuery *query = NULL;
928 ModestMailOperationPrivate *priv = NULL;
929 ModestTnySendQueue *send_queue = NULL;
931 info = (UpdateAccountInfo *) thr_user_data;
932 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
934 /* Get account and set it into mail_operation */
935 priv->account = g_object_ref (info->account);
938 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
939 * show any updates unless we do that
941 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
942 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
944 /* Get all the folders. We can do it synchronously because
945 we're already running in a different thread than the UI */
946 all_folders = tny_simple_list_new ();
947 query = tny_folder_store_query_new ();
948 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
949 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
954 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
958 iter = tny_list_create_iterator (all_folders);
959 while (!tny_iterator_is_done (iter)) {
960 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
962 recurse_folders (folder, query, all_folders);
963 tny_iterator_next (iter);
965 g_object_unref (G_OBJECT (iter));
967 /* Update status and notify. We need to call the notification
968 with a source function in order to call it from the main
969 loop. We need that in order not to get into trouble with
970 Gtk+. We use a timeout in order to provide more status
971 information, because the sync tinymail call does not
972 provide it for the moment */
973 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
975 /* Refresh folders */
976 new_headers = g_ptr_array_new ();
977 iter = tny_list_create_iterator (all_folders);
979 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
981 InternalFolderObserver *observer;
982 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
984 /* Refresh the folder */
985 /* Our observer receives notification of new emails during folder refreshes,
986 * so we can use observer->new_headers.
988 observer = g_object_new (internal_folder_observer_get_type (), NULL);
989 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
991 /* This gets the status information (headers) from the server.
992 * We use the blocking version, because we are already in a separate
996 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
997 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1000 /* If the retrieve type is full messages, refresh and get the messages */
1001 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1003 iter = tny_list_create_iterator (observer->new_headers);
1004 while (!tny_iterator_is_done (iter)) {
1005 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1007 /* Apply per-message size limits */
1008 if (tny_header_get_message_size (header) < info->max_size)
1009 g_ptr_array_add (new_headers, g_object_ref (header));
1011 g_object_unref (header);
1012 tny_iterator_next (iter);
1014 g_object_unref (iter);
1016 /* We do not need to do it the first time
1017 because it's automatically done by the tree
1019 if (G_UNLIKELY (!first_time))
1020 tny_folder_poke_status (TNY_FOLDER (folder));
1022 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1023 g_object_unref (observer);
1026 g_object_unref (G_OBJECT (folder));
1029 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1033 tny_iterator_next (iter);
1036 did_a_cancel = FALSE;
1038 g_object_unref (G_OBJECT (iter));
1039 g_source_remove (timeout);
1041 if (new_headers->len > 0) {
1045 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1047 /* Apply message count limit */
1048 /* If the number of messages exceeds the maximum, ask the
1049 * user to download them all,
1050 * as per the UI spec "Retrieval Limits" section in 4.4:
1052 if (new_headers->len > info->retrieve_limit) {
1053 /* TODO: Ask the user, instead of just
1055 * mail_nc_msg_count_limit_exceeded, with 'Get
1056 * all' and 'Newest only' buttons. */
1057 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1058 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1059 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1060 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1061 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1066 priv->total = MIN (new_headers->len, info->retrieve_limit);
1067 while (msg_num < priv->total) {
1069 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1070 TnyFolder *folder = tny_header_get_folder (header);
1071 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1072 ModestMailOperationState *state;
1076 /* We can not just use the mail operation because the
1077 values of done and total could change before the
1079 state = modest_mail_operation_clone_state (info->mail_op);
1080 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1081 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1082 pair, (GDestroyNotify) modest_pair_free);
1084 g_object_unref (msg);
1085 g_object_unref (folder);
1089 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1090 g_ptr_array_free (new_headers, FALSE);
1094 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1097 if (priv->account != NULL)
1098 g_object_unref (priv->account);
1099 priv->account = g_object_ref (info->transport_account);
1101 send_queue = modest_runtime_get_send_queue (info->transport_account);
1103 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
1104 modest_tny_send_queue_try_to_send (send_queue);
1105 g_source_remove (timeout);
1107 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1108 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1109 "cannot create a send queue for %s\n",
1110 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1111 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1114 /* Check if the operation was a success */
1116 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1118 /* Update the last updated key */
1119 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1120 set_last_updated_idle,
1121 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1122 (GDestroyNotify) g_free);
1127 if (info->callback) {
1128 UpdateAccountInfo *idle_info;
1130 /* This thread is not in the main lock */
1131 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1132 idle_info->mail_op = g_object_ref (info->mail_op);
1133 idle_info->new_headers = (new_headers) ? new_headers->len : 0;
1134 idle_info->callback = info->callback;
1135 g_idle_add (idle_update_account_cb, idle_info);
1138 /* Notify about operation end. Note that the info could be
1139 freed before this idle happens, but the mail operation will
1141 g_idle_add (idle_notify_update_account_queue, g_object_ref (info->mail_op));
1144 g_object_unref (query);
1145 g_object_unref (all_folders);
1146 g_object_unref (info->account);
1147 g_object_unref (info->transport_account);
1148 g_free (info->retrieve_type);
1149 g_slice_free (UpdateAccountInfo, info);
1157 modest_mail_operation_update_account (ModestMailOperation *self,
1158 const gchar *account_name,
1159 UpdateAccountCallback callback,
1163 UpdateAccountInfo *info;
1164 ModestMailOperationPrivate *priv;
1165 ModestAccountMgr *mgr;
1166 TnyStoreAccount *modest_account;
1167 TnyTransportAccount *transport_account;
1169 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1170 g_return_val_if_fail (account_name, FALSE);
1172 /* Init mail operation. Set total and done to 0, and do not
1173 update them, this way the progress objects will know that
1174 we have no clue about the number of the objects */
1175 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1178 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1180 /* Make sure that we have a connection, and request one
1182 * TODO: Is there some way to trigger this for every attempt to
1183 * use the network? */
1184 if (!modest_platform_connect_and_wait (NULL))
1187 /* Get the Modest account */
1188 modest_account = (TnyStoreAccount *)
1189 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1191 TNY_ACCOUNT_TYPE_STORE);
1193 if (!modest_account) {
1194 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1195 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1196 "cannot get tny store account for %s\n", account_name);
1201 /* Get the transport account, we can not do it in the thread
1202 due to some problems with dbus */
1203 transport_account = (TnyTransportAccount *)
1204 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1206 if (!transport_account) {
1207 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1208 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1209 "cannot get tny transport account for %s\n", account_name);
1213 /* Create the helper object */
1214 info = g_slice_new (UpdateAccountInfo);
1215 info->mail_op = self;
1216 info->account = modest_account;
1217 info->transport_account = transport_account;
1218 info->callback = callback;
1219 info->user_data = user_data;
1221 /* Get the message size limit */
1222 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1223 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1224 if (info->max_size == 0)
1225 info->max_size = G_MAXINT;
1227 info->max_size = info->max_size * KB;
1229 /* Get per-account retrieval type */
1230 mgr = modest_runtime_get_account_mgr ();
1231 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1232 MODEST_ACCOUNT_RETRIEVE, FALSE);
1234 /* Get per-account message amount retrieval limit */
1235 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1236 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1237 if (info->retrieve_limit == 0)
1238 info->retrieve_limit = G_MAXINT;
1240 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1242 /* Set account busy */
1243 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1244 priv->account_name = g_strdup(account_name);
1246 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1251 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1253 callback (self, 0, user_data);
1254 modest_mail_operation_notify_end (self);
1258 /* ******************************************************************* */
1259 /* ************************** STORE ACTIONS ************************* */
1260 /* ******************************************************************* */
1264 modest_mail_operation_create_folder (ModestMailOperation *self,
1265 TnyFolderStore *parent,
1268 ModestMailOperationPrivate *priv;
1269 TnyFolder *new_folder = NULL;
1271 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1272 g_return_val_if_fail (name, NULL);
1274 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1277 if (TNY_IS_FOLDER (parent)) {
1278 /* Check folder rules */
1279 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1280 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1281 /* Set status failed and set an error */
1282 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1283 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1284 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1285 _("mail_in_ui_folder_create_error"));
1289 if (!strcmp (name, " ") || strchr (name, '/')) {
1290 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1291 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1292 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1293 _("mail_in_ui_folder_create_error"));
1297 /* Create the folder */
1298 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1299 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1301 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1304 /* Notify about operation end */
1305 modest_mail_operation_notify_end (self);
1311 modest_mail_operation_remove_folder (ModestMailOperation *self,
1313 gboolean remove_to_trash)
1315 TnyAccount *account;
1316 ModestMailOperationPrivate *priv;
1317 ModestTnyFolderRules rules;
1319 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1320 g_return_if_fail (TNY_IS_FOLDER (folder));
1322 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1324 /* Check folder rules */
1325 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1326 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1327 /* Set status failed and set an error */
1328 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1329 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1330 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1331 _("mail_in_ui_folder_delete_error"));
1335 /* Get the account */
1336 account = modest_tny_folder_get_account (folder);
1337 priv->account = g_object_ref(account);
1339 /* Delete folder or move to trash */
1340 if (remove_to_trash) {
1341 TnyFolder *trash_folder = NULL;
1342 trash_folder = modest_tny_account_get_special_folder (account,
1343 TNY_FOLDER_TYPE_TRASH);
1344 /* TODO: error_handling */
1345 modest_mail_operation_xfer_folder (self, folder,
1346 TNY_FOLDER_STORE (trash_folder),
1349 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1351 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1352 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1355 g_object_unref (G_OBJECT (parent));
1357 g_object_unref (G_OBJECT (account));
1360 /* Notify about operation end */
1361 modest_mail_operation_notify_end (self);
1365 transfer_folder_status_cb (GObject *obj,
1369 ModestMailOperation *self;
1370 ModestMailOperationPrivate *priv;
1371 ModestMailOperationState *state;
1372 XFerMsgAsyncHelper *helper;
1374 g_return_if_fail (status != NULL);
1375 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1377 helper = (XFerMsgAsyncHelper *) user_data;
1378 g_return_if_fail (helper != NULL);
1380 self = helper->mail_op;
1381 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1383 priv->done = status->position;
1384 priv->total = status->of_total;
1386 state = modest_mail_operation_clone_state (self);
1387 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1388 g_slice_free (ModestMailOperationState, state);
1393 transfer_folder_cb (TnyFolder *folder,
1394 TnyFolderStore *into,
1396 TnyFolder *new_folder,
1400 XFerMsgAsyncHelper *helper;
1401 ModestMailOperation *self = NULL;
1402 ModestMailOperationPrivate *priv = NULL;
1404 helper = (XFerMsgAsyncHelper *) user_data;
1405 g_return_if_fail (helper != NULL);
1407 self = helper->mail_op;
1408 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1411 priv->error = g_error_copy (*err);
1413 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1414 } else if (cancelled) {
1415 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1416 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1417 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1418 _("Transference of %s was cancelled."),
1419 tny_folder_get_name (folder));
1422 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1425 /* Notify about operation end */
1426 modest_mail_operation_notify_end (self);
1428 /* If user defined callback function was defined, call it */
1429 if (helper->user_callback) {
1430 gdk_threads_enter ();
1431 helper->user_callback (priv->source, helper->user_data);
1432 gdk_threads_leave ();
1436 g_object_unref (helper->mail_op);
1437 g_slice_free (XFerMsgAsyncHelper, helper);
1438 g_object_unref (folder);
1439 g_object_unref (into);
1443 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1445 TnyFolderStore *parent,
1446 gboolean delete_original,
1447 XferMsgsAsynUserCallback user_callback,
1450 ModestMailOperationPrivate *priv = NULL;
1451 ModestTnyFolderRules parent_rules = 0, rules;
1452 XFerMsgAsyncHelper *helper = NULL;
1454 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1455 g_return_if_fail (TNY_IS_FOLDER (folder));
1457 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1459 /* Get account and set it into mail_operation */
1460 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1461 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1463 /* Get folder rules */
1464 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1465 if (TNY_IS_FOLDER (parent))
1466 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1468 /* The moveable restriction is applied also to copy operation */
1469 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1470 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1471 /* Set status failed and set an error */
1472 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1473 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1474 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1475 _("mail_in_ui_folder_move_target_error"));
1477 /* Notify the queue */
1478 modest_mail_operation_notify_end (self);
1479 } else if (TNY_IS_FOLDER (parent) &&
1480 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1481 /* Set status failed and set an error */
1482 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1483 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1484 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1485 _("FIXME: parent folder does not accept new folders"));
1487 /* Notify the queue */
1488 modest_mail_operation_notify_end (self);
1490 /* Pick references for async calls */
1491 g_object_ref (folder);
1492 g_object_ref (parent);
1494 /* Create the helper */
1495 helper = g_slice_new0 (XFerMsgAsyncHelper);
1496 helper->mail_op = g_object_ref(self);
1497 helper->dest_folder = NULL;
1498 helper->headers = NULL;
1499 helper->user_callback = user_callback;
1500 helper->user_data = user_data;
1502 /* Move/Copy folder */
1503 tny_folder_copy_async (folder,
1505 tny_folder_get_name (folder),
1508 transfer_folder_status_cb,
1515 modest_mail_operation_rename_folder (ModestMailOperation *self,
1519 ModestMailOperationPrivate *priv;
1520 ModestTnyFolderRules rules;
1521 XFerMsgAsyncHelper *helper;
1523 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1524 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1525 g_return_if_fail (name);
1527 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1529 /* Get account and set it into mail_operation */
1530 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1532 /* Check folder rules */
1533 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1534 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1535 /* Set status failed and set an error */
1536 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1537 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1538 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1539 _("FIXME: unable to rename"));
1541 /* Notify about operation end */
1542 modest_mail_operation_notify_end (self);
1543 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1544 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1545 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1546 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1547 _("FIXME: unable to rename"));
1548 /* Notify about operation end */
1549 modest_mail_operation_notify_end (self);
1551 TnyFolderStore *into;
1553 /* Create the helper */
1554 helper = g_slice_new0 (XFerMsgAsyncHelper);
1555 helper->mail_op = g_object_ref(self);
1556 helper->dest_folder = NULL;
1557 helper->headers = NULL;
1558 helper->user_callback = NULL;
1559 helper->user_data = NULL;
1561 /* Rename. Camel handles folder subscription/unsubscription */
1562 into = tny_folder_get_folder_store (folder);
1563 tny_folder_copy_async (folder, into, name, TRUE,
1565 transfer_folder_status_cb,
1569 g_object_unref (into);
1573 /* ******************************************************************* */
1574 /* ************************** MSG ACTIONS ************************* */
1575 /* ******************************************************************* */
1577 void modest_mail_operation_get_msg (ModestMailOperation *self,
1579 GetMsgAsyncUserCallback user_callback,
1582 GetMsgAsyncHelper *helper = NULL;
1584 ModestMailOperationPrivate *priv;
1586 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1587 g_return_if_fail (TNY_IS_HEADER (header));
1589 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1590 folder = tny_header_get_folder (header);
1592 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1594 /* Get message from folder */
1596 /* Get account and set it into mail_operation */
1597 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1599 helper = g_slice_new0 (GetMsgAsyncHelper);
1600 helper->mail_op = self;
1601 helper->user_callback = user_callback;
1602 helper->user_data = user_data;
1603 helper->header = g_object_ref (header);
1605 // The callback's reference so that the mail op is not
1606 // finalized until the async operation is completed even if
1607 // the user canceled the request meanwhile.
1608 g_object_ref (G_OBJECT (helper->mail_op));
1610 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1612 g_object_unref (G_OBJECT (folder));
1614 /* Set status failed and set an error */
1615 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1616 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1617 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1618 _("Error trying to get a message. No folder found for header"));
1620 /* Notify the queue */
1621 modest_mail_operation_notify_end (self);
1626 get_msg_cb (TnyFolder *folder,
1632 GetMsgAsyncHelper *helper = NULL;
1633 ModestMailOperation *self = NULL;
1634 ModestMailOperationPrivate *priv = NULL;
1636 helper = (GetMsgAsyncHelper *) user_data;
1637 g_return_if_fail (helper != NULL);
1638 self = helper->mail_op;
1639 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1640 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1642 /* Check errors and cancel */
1644 priv->error = g_error_copy (*error);
1645 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1646 } else if (cancelled) {
1647 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1648 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1649 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1650 _("Error trying to refresh the contents of %s"),
1651 tny_folder_get_name (folder));
1653 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1656 /* If user defined callback function was defined, call it even
1657 if the operation failed*/
1658 if (helper->user_callback) {
1659 /* This callback is called into an iddle by tinymail,
1660 and idles are not in the main lock */
1661 gdk_threads_enter ();
1662 helper->user_callback (self, helper->header, msg, helper->user_data);
1663 gdk_threads_leave ();
1667 g_object_unref (helper->mail_op);
1668 g_object_unref (helper->header);
1669 g_slice_free (GetMsgAsyncHelper, helper);
1671 /* Notify about operation end */
1672 modest_mail_operation_notify_end (self);
1676 get_msg_status_cb (GObject *obj,
1680 GetMsgAsyncHelper *helper = NULL;
1681 ModestMailOperation *self;
1682 ModestMailOperationPrivate *priv;
1683 ModestMailOperationState *state;
1685 g_return_if_fail (status != NULL);
1686 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1688 helper = (GetMsgAsyncHelper *) user_data;
1689 g_return_if_fail (helper != NULL);
1691 self = helper->mail_op;
1692 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1694 if(priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1700 state = modest_mail_operation_clone_state (self);
1701 state->bytes_done = status->position;
1702 state->bytes_total = status->of_total;
1703 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1704 g_slice_free (ModestMailOperationState, state);
1707 /****************************************************/
1709 ModestMailOperation *mail_op;
1711 GetMsgAsyncUserCallback user_callback;
1713 GDestroyNotify notify;
1717 GetMsgAsyncUserCallback user_callback;
1721 ModestMailOperation *mail_op;
1722 } NotifyGetMsgsInfo;
1726 * Used by get_msgs_full_thread to call the user_callback for each
1727 * message that has been read
1730 notify_get_msgs_full (gpointer data)
1732 NotifyGetMsgsInfo *info;
1734 info = (NotifyGetMsgsInfo *) data;
1736 /* Call the user callback. Idles are not in the main lock, so
1738 gdk_threads_enter ();
1739 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1740 gdk_threads_leave ();
1742 g_slice_free (NotifyGetMsgsInfo, info);
1748 * Used by get_msgs_full_thread to free al the thread resources and to
1749 * call the destroy function for the passed user_data
1752 get_msgs_full_destroyer (gpointer data)
1754 GetFullMsgsInfo *info;
1756 info = (GetFullMsgsInfo *) data;
1759 gdk_threads_enter ();
1760 info->notify (info->user_data);
1761 gdk_threads_leave ();
1765 g_object_unref (info->headers);
1766 g_slice_free (GetFullMsgsInfo, info);
1772 get_msgs_full_thread (gpointer thr_user_data)
1774 GetFullMsgsInfo *info;
1775 ModestMailOperationPrivate *priv = NULL;
1776 TnyIterator *iter = NULL;
1778 info = (GetFullMsgsInfo *) thr_user_data;
1779 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1781 iter = tny_list_create_iterator (info->headers);
1782 while (!tny_iterator_is_done (iter)) {
1786 header = TNY_HEADER (tny_iterator_get_current (iter));
1787 folder = tny_header_get_folder (header);
1789 /* Get message from folder */
1792 /* The callback will call it per each header */
1793 msg = tny_folder_get_msg (folder, header, &(priv->error));
1796 ModestMailOperationState *state;
1801 /* notify progress */
1802 state = modest_mail_operation_clone_state (info->mail_op);
1803 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1804 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1805 pair, (GDestroyNotify) modest_pair_free);
1807 /* The callback is the responsible for
1808 freeing the message */
1809 if (info->user_callback) {
1810 NotifyGetMsgsInfo *info_notify;
1811 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1812 info_notify->user_callback = info->user_callback;
1813 info_notify->mail_op = info->mail_op;
1814 info_notify->header = g_object_ref (header);
1815 info_notify->msg = g_object_ref (msg);
1816 info_notify->user_data = info->user_data;
1817 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1818 notify_get_msgs_full,
1821 g_object_unref (msg);
1824 /* Set status failed and set an error */
1825 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1826 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1827 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1828 "Error trying to get a message. No folder found for header");
1830 g_object_unref (header);
1831 tny_iterator_next (iter);
1834 /* Set operation status */
1835 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1836 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1838 /* Notify about operation end */
1839 g_idle_add (idle_notify_update_account_queue, g_object_ref (info->mail_op));
1841 /* Free thread resources. Will be called after all previous idles */
1842 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1848 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1849 TnyList *header_list,
1850 GetMsgAsyncUserCallback user_callback,
1852 GDestroyNotify notify)
1854 TnyHeader *header = NULL;
1855 TnyFolder *folder = NULL;
1857 ModestMailOperationPrivate *priv = NULL;
1858 GetFullMsgsInfo *info = NULL;
1859 gboolean size_ok = TRUE;
1861 TnyIterator *iter = NULL;
1863 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1865 /* Init mail operation */
1866 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1867 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1869 priv->total = tny_list_get_length(header_list);
1871 /* Get account and set it into mail_operation */
1872 if (tny_list_get_length (header_list) >= 1) {
1873 iter = tny_list_create_iterator (header_list);
1874 header = TNY_HEADER (tny_iterator_get_current (iter));
1875 folder = tny_header_get_folder (header);
1876 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1877 g_object_unref (header);
1878 g_object_unref (folder);
1880 if (tny_list_get_length (header_list) == 1) {
1881 g_object_unref (iter);
1886 /* Get msg size limit */
1887 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1888 MODEST_CONF_MSG_SIZE_LIMIT,
1891 g_clear_error (&(priv->error));
1892 max_size = G_MAXINT;
1894 max_size = max_size * KB;
1897 /* Check message size limits. If there is only one message
1898 always retrieve it */
1900 while (!tny_iterator_is_done (iter) && size_ok) {
1901 header = TNY_HEADER (tny_iterator_get_current (iter));
1902 if (tny_header_get_message_size (header) >= max_size)
1904 g_object_unref (header);
1905 tny_iterator_next (iter);
1907 g_object_unref (iter);
1911 /* Create the info */
1912 info = g_slice_new0 (GetFullMsgsInfo);
1913 info->mail_op = self;
1914 info->user_callback = user_callback;
1915 info->user_data = user_data;
1916 info->headers = g_object_ref (header_list);
1917 info->notify = notify;
1919 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1921 /* Set status failed and set an error */
1922 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1923 /* FIXME: the error msg is different for pop */
1924 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1925 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1926 _("emev_ni_ui_imap_msg_size_exceed_error"));
1927 /* Remove from queue and free resources */
1928 modest_mail_operation_notify_end (self);
1936 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
1937 gboolean remove_to_trash /*ignored*/)
1940 ModestMailOperationPrivate *priv;
1942 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1943 g_return_if_fail (TNY_IS_HEADER (header));
1945 if (remove_to_trash)
1946 g_warning ("remove to trash is not implemented");
1948 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1949 folder = tny_header_get_folder (header);
1951 /* Get account and set it into mail_operation */
1952 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1954 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1957 tny_folder_remove_msg (folder, header, &(priv->error));
1959 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
1961 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
1962 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
1963 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
1964 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
1967 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
1973 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1975 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1978 g_object_unref (G_OBJECT (folder));
1980 /* Notify about operation end */
1981 modest_mail_operation_notify_end (self);
1985 transfer_msgs_status_cb (GObject *obj,
1989 XFerMsgAsyncHelper *helper = NULL;
1990 ModestMailOperation *self;
1991 ModestMailOperationPrivate *priv;
1992 ModestMailOperationState *state;
1995 g_return_if_fail (status != NULL);
1996 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1998 helper = (XFerMsgAsyncHelper *) user_data;
1999 g_return_if_fail (helper != NULL);
2001 self = helper->mail_op;
2002 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2004 priv->done = status->position;
2005 priv->total = status->of_total;
2007 state = modest_mail_operation_clone_state (self);
2008 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2009 g_slice_free (ModestMailOperationState, state);
2014 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2016 XFerMsgAsyncHelper *helper;
2017 ModestMailOperation *self;
2018 ModestMailOperationPrivate *priv;
2020 helper = (XFerMsgAsyncHelper *) user_data;
2021 self = helper->mail_op;
2023 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2026 priv->error = g_error_copy (*err);
2028 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2029 } else if (cancelled) {
2030 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2031 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2032 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2033 _("Error trying to refresh the contents of %s"),
2034 tny_folder_get_name (folder));
2037 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2040 /* Notify about operation end */
2041 modest_mail_operation_notify_end (self);
2043 /* If user defined callback function was defined, call it */
2044 if (helper->user_callback) {
2045 gdk_threads_enter ();
2046 helper->user_callback (priv->source, helper->user_data);
2047 gdk_threads_leave ();
2051 g_object_unref (helper->headers);
2052 g_object_unref (helper->dest_folder);
2053 g_object_unref (helper->mail_op);
2054 g_slice_free (XFerMsgAsyncHelper, helper);
2055 g_object_unref (folder);
2060 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2063 gboolean delete_original,
2064 XferMsgsAsynUserCallback user_callback,
2067 ModestMailOperationPrivate *priv;
2069 TnyFolder *src_folder;
2070 XFerMsgAsyncHelper *helper;
2072 ModestTnyFolderRules rules;
2073 const gchar *id1 = NULL;
2074 const gchar *id2 = NULL;
2075 gboolean same_folder = FALSE;
2077 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2078 g_return_if_fail (TNY_IS_LIST (headers));
2079 g_return_if_fail (TNY_IS_FOLDER (folder));
2081 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2084 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2086 /* Apply folder rules */
2087 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2088 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2089 /* Set status failed and set an error */
2090 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2091 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2092 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2093 _("ckct_ib_unable_to_paste_here"));
2094 /* Notify the queue */
2095 modest_mail_operation_notify_end (self);
2099 /* Get source folder */
2100 iter = tny_list_create_iterator (headers);
2101 header = TNY_HEADER (tny_iterator_get_current (iter));
2102 src_folder = tny_header_get_folder (header);
2103 g_object_unref (header);
2104 g_object_unref (iter);
2106 /* Check folder source and destination */
2107 id1 = tny_folder_get_id (src_folder);
2108 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2109 same_folder = !g_ascii_strcasecmp (id1, id2);
2111 /* Set status failed and set an error */
2112 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2113 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2114 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2115 _("mcen_ib_unable_to_copy_samefolder"));
2117 /* Notify the queue */
2118 modest_mail_operation_notify_end (self);
2121 g_object_unref (src_folder);
2125 /* Create the helper */
2126 helper = g_slice_new0 (XFerMsgAsyncHelper);
2127 helper->mail_op = g_object_ref(self);
2128 helper->dest_folder = g_object_ref(folder);
2129 helper->headers = g_object_ref(headers);
2130 helper->user_callback = user_callback;
2131 helper->user_data = user_data;
2133 /* Get account and set it into mail_operation */
2134 priv->account = modest_tny_folder_get_account (src_folder);
2136 /* Transfer messages */
2137 tny_folder_transfer_msgs_async (src_folder,
2142 transfer_msgs_status_cb,
2148 on_refresh_folder (TnyFolder *folder,
2153 RefreshAsyncHelper *helper = NULL;
2154 ModestMailOperation *self = NULL;
2155 ModestMailOperationPrivate *priv = NULL;
2157 helper = (RefreshAsyncHelper *) user_data;
2158 self = helper->mail_op;
2159 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2162 priv->error = g_error_copy (*error);
2163 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2168 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2169 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2170 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2171 _("Error trying to refresh the contents of %s"),
2172 tny_folder_get_name (folder));
2176 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2179 /* Call user defined callback, if it exists */
2180 if (helper->user_callback) {
2181 gdk_threads_enter ();
2182 helper->user_callback (self, folder, helper->user_data);
2183 gdk_threads_leave ();
2187 g_object_unref (helper->mail_op);
2188 g_slice_free (RefreshAsyncHelper, helper);
2189 g_object_unref (folder);
2191 /* Notify about operation end */
2192 modest_mail_operation_notify_end (self);
2196 on_refresh_folder_status_update (GObject *obj,
2200 RefreshAsyncHelper *helper = NULL;
2201 ModestMailOperation *self = NULL;
2202 ModestMailOperationPrivate *priv = NULL;
2203 ModestMailOperationState *state;
2205 g_return_if_fail (user_data != NULL);
2206 g_return_if_fail (status != NULL);
2207 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2209 helper = (RefreshAsyncHelper *) user_data;
2210 self = helper->mail_op;
2211 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2213 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2215 priv->done = status->position;
2216 priv->total = status->of_total;
2218 state = modest_mail_operation_clone_state (self);
2219 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2220 g_slice_free (ModestMailOperationState, state);
2224 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2226 RefreshAsyncUserCallback user_callback,
2229 ModestMailOperationPrivate *priv = NULL;
2230 RefreshAsyncHelper *helper = NULL;
2232 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2234 /* Pick a reference */
2235 g_object_ref (folder);
2237 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2239 /* Get account and set it into mail_operation */
2240 priv->account = modest_tny_folder_get_account (folder);
2242 /* Create the helper */
2243 helper = g_slice_new0 (RefreshAsyncHelper);
2244 helper->mail_op = g_object_ref(self);
2245 helper->user_callback = user_callback;
2246 helper->user_data = user_data;
2248 /* Refresh the folder. TODO: tinymail could issue a status
2249 updates before the callback call then this could happen. We
2250 must review the design */
2251 tny_folder_refresh_async (folder,
2253 on_refresh_folder_status_update,
2259 * It's used by the mail operation queue to notify the observers
2260 * attached to that signal that the operation finished. We need to use
2261 * that because tinymail does not give us the progress of a given
2262 * operation when it finishes (it directly calls the operation
2266 modest_mail_operation_notify_end (ModestMailOperation *self)
2268 ModestMailOperationState *state;
2269 ModestMailOperationPrivate *priv = NULL;
2271 g_return_if_fail (self);
2273 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2276 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
2280 /* Set the account back to not busy */
2281 if (priv->account_name) {
2282 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2283 priv->account_name, FALSE);
2284 g_free(priv->account_name);
2285 priv->account_name = NULL;
2288 /* Notify the observers about the mail opertation end */
2289 state = modest_mail_operation_clone_state (self);
2290 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2291 g_slice_free (ModestMailOperationState, state);