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 /* Get the Modest account */
1181 modest_account = (TnyStoreAccount *)
1182 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1184 TNY_ACCOUNT_TYPE_STORE);
1186 if (!modest_account) {
1187 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1188 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1189 "cannot get tny store account for %s\n", account_name);
1194 /* Get the transport account, we can not do it in the thread
1195 due to some problems with dbus */
1196 transport_account = (TnyTransportAccount *)
1197 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1199 if (!transport_account) {
1200 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1201 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1202 "cannot get tny transport account for %s\n", account_name);
1206 /* Create the helper object */
1207 info = g_slice_new (UpdateAccountInfo);
1208 info->mail_op = self;
1209 info->account = modest_account;
1210 info->transport_account = transport_account;
1211 info->callback = callback;
1212 info->user_data = user_data;
1214 /* Get the message size limit */
1215 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1216 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1217 if (info->max_size == 0)
1218 info->max_size = G_MAXINT;
1220 info->max_size = info->max_size * KB;
1222 /* Get per-account retrieval type */
1223 mgr = modest_runtime_get_account_mgr ();
1224 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1225 MODEST_ACCOUNT_RETRIEVE, FALSE);
1227 /* Get per-account message amount retrieval limit */
1228 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1229 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1230 if (info->retrieve_limit == 0)
1231 info->retrieve_limit = G_MAXINT;
1233 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1235 /* Set account busy */
1236 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1237 priv->account_name = g_strdup(account_name);
1239 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1244 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1246 callback (self, 0, user_data);
1247 modest_mail_operation_notify_end (self);
1251 /* ******************************************************************* */
1252 /* ************************** STORE ACTIONS ************************* */
1253 /* ******************************************************************* */
1257 modest_mail_operation_create_folder (ModestMailOperation *self,
1258 TnyFolderStore *parent,
1261 ModestMailOperationPrivate *priv;
1262 TnyFolder *new_folder = NULL;
1264 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1265 g_return_val_if_fail (name, NULL);
1267 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1270 if (TNY_IS_FOLDER (parent)) {
1271 /* Check folder rules */
1272 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1273 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1274 /* Set status failed and set an error */
1275 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1276 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1277 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1278 _("mail_in_ui_folder_create_error"));
1282 if (!strcmp (name, " ") || strchr (name, '/')) {
1283 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1284 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1285 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1286 _("mail_in_ui_folder_create_error"));
1290 /* Create the folder */
1291 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1292 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1294 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1297 /* Notify about operation end */
1298 modest_mail_operation_notify_end (self);
1304 modest_mail_operation_remove_folder (ModestMailOperation *self,
1306 gboolean remove_to_trash)
1308 TnyAccount *account;
1309 ModestMailOperationPrivate *priv;
1310 ModestTnyFolderRules rules;
1312 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1313 g_return_if_fail (TNY_IS_FOLDER (folder));
1315 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1317 /* Check folder rules */
1318 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1319 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1320 /* Set status failed and set an error */
1321 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1322 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1323 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1324 _("mail_in_ui_folder_delete_error"));
1328 /* Get the account */
1329 account = modest_tny_folder_get_account (folder);
1330 priv->account = g_object_ref(account);
1332 /* Delete folder or move to trash */
1333 if (remove_to_trash) {
1334 TnyFolder *trash_folder = NULL;
1335 trash_folder = modest_tny_account_get_special_folder (account,
1336 TNY_FOLDER_TYPE_TRASH);
1337 /* TODO: error_handling */
1338 modest_mail_operation_xfer_folder (self, folder,
1339 TNY_FOLDER_STORE (trash_folder),
1342 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1344 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1345 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1348 g_object_unref (G_OBJECT (parent));
1350 g_object_unref (G_OBJECT (account));
1353 /* Notify about operation end */
1354 modest_mail_operation_notify_end (self);
1358 transfer_folder_status_cb (GObject *obj,
1362 ModestMailOperation *self;
1363 ModestMailOperationPrivate *priv;
1364 ModestMailOperationState *state;
1365 XFerMsgAsyncHelper *helper;
1367 g_return_if_fail (status != NULL);
1368 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1370 helper = (XFerMsgAsyncHelper *) user_data;
1371 g_return_if_fail (helper != NULL);
1373 self = helper->mail_op;
1374 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1376 priv->done = status->position;
1377 priv->total = status->of_total;
1379 state = modest_mail_operation_clone_state (self);
1380 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1381 g_slice_free (ModestMailOperationState, state);
1386 transfer_folder_cb (TnyFolder *folder,
1387 TnyFolderStore *into,
1389 TnyFolder *new_folder,
1393 XFerMsgAsyncHelper *helper;
1394 ModestMailOperation *self = NULL;
1395 ModestMailOperationPrivate *priv = NULL;
1397 helper = (XFerMsgAsyncHelper *) user_data;
1398 g_return_if_fail (helper != NULL);
1400 self = helper->mail_op;
1401 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1404 priv->error = g_error_copy (*err);
1406 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1407 } else if (cancelled) {
1408 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1409 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1410 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1411 _("Transference of %s was cancelled."),
1412 tny_folder_get_name (folder));
1415 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1418 /* Notify about operation end */
1419 modest_mail_operation_notify_end (self);
1421 /* If user defined callback function was defined, call it */
1422 if (helper->user_callback) {
1423 gdk_threads_enter ();
1424 helper->user_callback (priv->source, helper->user_data);
1425 gdk_threads_leave ();
1429 g_object_unref (helper->mail_op);
1430 g_slice_free (XFerMsgAsyncHelper, helper);
1431 g_object_unref (folder);
1432 g_object_unref (into);
1436 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1438 TnyFolderStore *parent,
1439 gboolean delete_original,
1440 XferMsgsAsynUserCallback user_callback,
1443 ModestMailOperationPrivate *priv = NULL;
1444 ModestTnyFolderRules parent_rules = 0, rules;
1445 XFerMsgAsyncHelper *helper = NULL;
1447 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1448 g_return_if_fail (TNY_IS_FOLDER (folder));
1450 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1452 /* Get account and set it into mail_operation */
1453 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1454 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1456 /* Get folder rules */
1457 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1458 if (TNY_IS_FOLDER (parent))
1459 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1461 /* The moveable restriction is applied also to copy operation */
1462 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1463 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1464 /* Set status failed and set an error */
1465 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1466 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1467 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1468 _("mail_in_ui_folder_move_target_error"));
1470 /* Notify the queue */
1471 modest_mail_operation_notify_end (self);
1472 } else if (TNY_IS_FOLDER (parent) &&
1473 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1474 /* Set status failed and set an error */
1475 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1476 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1477 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1478 _("FIXME: parent folder does not accept new folders"));
1480 /* Notify the queue */
1481 modest_mail_operation_notify_end (self);
1483 /* Pick references for async calls */
1484 g_object_ref (folder);
1485 g_object_ref (parent);
1487 /* Create the helper */
1488 helper = g_slice_new0 (XFerMsgAsyncHelper);
1489 helper->mail_op = g_object_ref(self);
1490 helper->dest_folder = NULL;
1491 helper->headers = NULL;
1492 helper->user_callback = user_callback;
1493 helper->user_data = user_data;
1495 /* Move/Copy folder */
1496 tny_folder_copy_async (folder,
1498 tny_folder_get_name (folder),
1501 transfer_folder_status_cb,
1508 modest_mail_operation_rename_folder (ModestMailOperation *self,
1512 ModestMailOperationPrivate *priv;
1513 ModestTnyFolderRules rules;
1514 XFerMsgAsyncHelper *helper;
1516 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1517 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1518 g_return_if_fail (name);
1520 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1522 /* Get account and set it into mail_operation */
1523 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1525 /* Check folder rules */
1526 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1527 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1528 /* Set status failed and set an error */
1529 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1530 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1531 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1532 _("FIXME: unable to rename"));
1534 /* Notify about operation end */
1535 modest_mail_operation_notify_end (self);
1536 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1537 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1538 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1539 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1540 _("FIXME: unable to rename"));
1541 /* Notify about operation end */
1542 modest_mail_operation_notify_end (self);
1544 TnyFolderStore *into;
1546 /* Create the helper */
1547 helper = g_slice_new0 (XFerMsgAsyncHelper);
1548 helper->mail_op = g_object_ref(self);
1549 helper->dest_folder = NULL;
1550 helper->headers = NULL;
1551 helper->user_callback = NULL;
1552 helper->user_data = NULL;
1554 /* Rename. Camel handles folder subscription/unsubscription */
1555 into = tny_folder_get_folder_store (folder);
1556 tny_folder_copy_async (folder, into, name, TRUE,
1558 transfer_folder_status_cb,
1562 g_object_unref (into);
1566 /* ******************************************************************* */
1567 /* ************************** MSG ACTIONS ************************* */
1568 /* ******************************************************************* */
1570 void modest_mail_operation_get_msg (ModestMailOperation *self,
1572 GetMsgAsyncUserCallback user_callback,
1575 GetMsgAsyncHelper *helper = NULL;
1577 ModestMailOperationPrivate *priv;
1579 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1580 g_return_if_fail (TNY_IS_HEADER (header));
1582 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1583 folder = tny_header_get_folder (header);
1585 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1587 /* Get message from folder */
1589 /* Get account and set it into mail_operation */
1590 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1592 helper = g_slice_new0 (GetMsgAsyncHelper);
1593 helper->mail_op = self;
1594 helper->user_callback = user_callback;
1595 helper->user_data = user_data;
1596 helper->header = g_object_ref (header);
1598 // The callback's reference so that the mail op is not
1599 // finalized until the async operation is completed even if
1600 // the user canceled the request meanwhile.
1601 g_object_ref (G_OBJECT (helper->mail_op));
1603 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1605 g_object_unref (G_OBJECT (folder));
1607 /* Set status failed and set an error */
1608 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1609 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1610 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1611 _("Error trying to get a message. No folder found for header"));
1613 /* Notify the queue */
1614 modest_mail_operation_notify_end (self);
1619 get_msg_cb (TnyFolder *folder,
1625 GetMsgAsyncHelper *helper = NULL;
1626 ModestMailOperation *self = NULL;
1627 ModestMailOperationPrivate *priv = NULL;
1629 helper = (GetMsgAsyncHelper *) user_data;
1630 g_return_if_fail (helper != NULL);
1631 self = helper->mail_op;
1632 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1633 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1635 /* Check errors and cancel */
1637 priv->error = g_error_copy (*error);
1638 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1642 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1643 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1644 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1645 _("Error trying to refresh the contents of %s"),
1646 tny_folder_get_name (folder));
1650 /* The mail operation might have been canceled in which case we do not
1651 want to notify anyone anymore. */
1652 if(priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1653 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1655 /* If user defined callback function was defined, call it */
1656 if (helper->user_callback) {
1657 /* This callback is called into an iddle by tinymail,
1658 and idles are not in the main lock */
1659 gdk_threads_enter ();
1660 helper->user_callback (self, helper->header, msg, helper->user_data);
1661 gdk_threads_leave ();
1667 g_object_unref (helper->header);
1668 g_slice_free (GetMsgAsyncHelper, helper);
1670 /* Notify about operation end */
1671 if(priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED)
1672 modest_mail_operation_notify_end (self);
1674 g_object_unref (G_OBJECT (self));
1678 get_msg_status_cb (GObject *obj,
1682 GetMsgAsyncHelper *helper = NULL;
1683 ModestMailOperation *self;
1684 ModestMailOperationPrivate *priv;
1685 ModestMailOperationState *state;
1687 g_return_if_fail (status != NULL);
1688 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1690 helper = (GetMsgAsyncHelper *) user_data;
1691 g_return_if_fail (helper != NULL);
1693 self = helper->mail_op;
1694 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1696 if(priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1702 state = modest_mail_operation_clone_state (self);
1703 state->bytes_done = status->position;
1704 state->bytes_total = status->of_total;
1705 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1706 g_slice_free (ModestMailOperationState, state);
1709 /****************************************************/
1711 ModestMailOperation *mail_op;
1713 GetMsgAsyncUserCallback user_callback;
1715 GDestroyNotify notify;
1719 GetMsgAsyncUserCallback user_callback;
1723 ModestMailOperation *mail_op;
1724 } NotifyGetMsgsInfo;
1728 * Used by get_msgs_full_thread to call the user_callback for each
1729 * message that has been read
1732 notify_get_msgs_full (gpointer data)
1734 NotifyGetMsgsInfo *info;
1736 info = (NotifyGetMsgsInfo *) data;
1738 /* Call the user callback. Idles are not in the main lock, so
1740 gdk_threads_enter ();
1741 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1742 gdk_threads_leave ();
1744 g_slice_free (NotifyGetMsgsInfo, info);
1750 * Used by get_msgs_full_thread to free al the thread resources and to
1751 * call the destroy function for the passed user_data
1754 get_msgs_full_destroyer (gpointer data)
1756 GetFullMsgsInfo *info;
1758 info = (GetFullMsgsInfo *) data;
1761 gdk_threads_enter ();
1762 info->notify (info->user_data);
1763 gdk_threads_leave ();
1767 g_object_unref (info->headers);
1768 g_slice_free (GetFullMsgsInfo, info);
1774 get_msgs_full_thread (gpointer thr_user_data)
1776 GetFullMsgsInfo *info;
1777 ModestMailOperationPrivate *priv = NULL;
1778 TnyIterator *iter = NULL;
1780 info = (GetFullMsgsInfo *) thr_user_data;
1781 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1783 iter = tny_list_create_iterator (info->headers);
1784 while (!tny_iterator_is_done (iter)) {
1788 header = TNY_HEADER (tny_iterator_get_current (iter));
1789 folder = tny_header_get_folder (header);
1791 /* Get message from folder */
1794 /* The callback will call it per each header */
1795 msg = tny_folder_get_msg (folder, header, &(priv->error));
1798 ModestMailOperationState *state;
1803 /* notify progress */
1804 state = modest_mail_operation_clone_state (info->mail_op);
1805 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1806 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1807 pair, (GDestroyNotify) modest_pair_free);
1809 /* The callback is the responsible for
1810 freeing the message */
1811 if (info->user_callback) {
1812 NotifyGetMsgsInfo *info_notify;
1813 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1814 info_notify->user_callback = info->user_callback;
1815 info_notify->mail_op = info->mail_op;
1816 info_notify->header = g_object_ref (header);
1817 info_notify->msg = g_object_ref (msg);
1818 info_notify->user_data = info->user_data;
1819 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1820 notify_get_msgs_full,
1823 g_object_unref (msg);
1826 /* Set status failed and set an error */
1827 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1828 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1829 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1830 "Error trying to get a message. No folder found for header");
1832 g_object_unref (header);
1833 tny_iterator_next (iter);
1836 /* Set operation status */
1837 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1838 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1840 /* Notify about operation end */
1841 g_idle_add (idle_notify_update_account_queue, g_object_ref (info->mail_op));
1843 /* Free thread resources. Will be called after all previous idles */
1844 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1850 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1851 TnyList *header_list,
1852 GetMsgAsyncUserCallback user_callback,
1854 GDestroyNotify notify)
1856 TnyHeader *header = NULL;
1857 TnyFolder *folder = NULL;
1859 ModestMailOperationPrivate *priv = NULL;
1860 GetFullMsgsInfo *info = NULL;
1861 gboolean size_ok = TRUE;
1863 TnyIterator *iter = NULL;
1865 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1867 /* Init mail operation */
1868 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1869 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1871 priv->total = tny_list_get_length(header_list);
1873 /* Get account and set it into mail_operation */
1874 if (tny_list_get_length (header_list) >= 1) {
1875 iter = tny_list_create_iterator (header_list);
1876 header = TNY_HEADER (tny_iterator_get_current (iter));
1877 folder = tny_header_get_folder (header);
1878 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1879 g_object_unref (header);
1880 g_object_unref (folder);
1882 if (tny_list_get_length (header_list) == 1) {
1883 g_object_unref (iter);
1888 /* Get msg size limit */
1889 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1890 MODEST_CONF_MSG_SIZE_LIMIT,
1893 g_clear_error (&(priv->error));
1894 max_size = G_MAXINT;
1896 max_size = max_size * KB;
1899 /* Check message size limits. If there is only one message
1900 always retrieve it */
1902 while (!tny_iterator_is_done (iter) && size_ok) {
1903 header = TNY_HEADER (tny_iterator_get_current (iter));
1904 if (tny_header_get_message_size (header) >= max_size)
1906 g_object_unref (header);
1907 tny_iterator_next (iter);
1909 g_object_unref (iter);
1913 /* Create the info */
1914 info = g_slice_new0 (GetFullMsgsInfo);
1915 info->mail_op = self;
1916 info->user_callback = user_callback;
1917 info->user_data = user_data;
1918 info->headers = g_object_ref (header_list);
1919 info->notify = notify;
1921 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1923 /* Set status failed and set an error */
1924 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1925 /* FIXME: the error msg is different for pop */
1926 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1927 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1928 _("emev_ni_ui_imap_msg_size_exceed_error"));
1929 /* Remove from queue and free resources */
1930 modest_mail_operation_notify_end (self);
1938 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
1939 gboolean remove_to_trash /*ignored*/)
1942 ModestMailOperationPrivate *priv;
1944 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1945 g_return_if_fail (TNY_IS_HEADER (header));
1947 if (remove_to_trash)
1948 g_warning ("remove to trash is not implemented");
1950 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1951 folder = tny_header_get_folder (header);
1953 /* Get account and set it into mail_operation */
1954 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1956 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1959 tny_folder_remove_msg (folder, header, &(priv->error));
1961 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
1963 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
1964 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
1965 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
1966 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
1969 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
1975 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1977 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1980 g_object_unref (G_OBJECT (folder));
1982 /* Notify about operation end */
1983 modest_mail_operation_notify_end (self);
1987 transfer_msgs_status_cb (GObject *obj,
1991 XFerMsgAsyncHelper *helper = NULL;
1992 ModestMailOperation *self;
1993 ModestMailOperationPrivate *priv;
1994 ModestMailOperationState *state;
1997 g_return_if_fail (status != NULL);
1998 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2000 helper = (XFerMsgAsyncHelper *) user_data;
2001 g_return_if_fail (helper != NULL);
2003 self = helper->mail_op;
2004 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2006 priv->done = status->position;
2007 priv->total = status->of_total;
2009 state = modest_mail_operation_clone_state (self);
2010 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2011 g_slice_free (ModestMailOperationState, state);
2016 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2018 XFerMsgAsyncHelper *helper;
2019 ModestMailOperation *self;
2020 ModestMailOperationPrivate *priv;
2022 helper = (XFerMsgAsyncHelper *) user_data;
2023 self = helper->mail_op;
2025 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2028 priv->error = g_error_copy (*err);
2030 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2031 } else if (cancelled) {
2032 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2033 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2034 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2035 _("Error trying to refresh the contents of %s"),
2036 tny_folder_get_name (folder));
2039 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2042 /* Notify about operation end */
2043 modest_mail_operation_notify_end (self);
2045 /* If user defined callback function was defined, call it */
2046 if (helper->user_callback) {
2047 gdk_threads_enter ();
2048 helper->user_callback (priv->source, helper->user_data);
2049 gdk_threads_leave ();
2053 g_object_unref (helper->headers);
2054 g_object_unref (helper->dest_folder);
2055 g_object_unref (helper->mail_op);
2056 g_slice_free (XFerMsgAsyncHelper, helper);
2057 g_object_unref (folder);
2062 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2065 gboolean delete_original,
2066 XferMsgsAsynUserCallback user_callback,
2069 ModestMailOperationPrivate *priv;
2071 TnyFolder *src_folder;
2072 XFerMsgAsyncHelper *helper;
2074 ModestTnyFolderRules rules;
2075 const gchar *id1 = NULL;
2076 const gchar *id2 = NULL;
2077 gboolean same_folder = FALSE;
2079 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2080 g_return_if_fail (TNY_IS_LIST (headers));
2081 g_return_if_fail (TNY_IS_FOLDER (folder));
2083 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2086 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2088 /* Apply folder rules */
2089 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2090 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2091 /* Set status failed and set an error */
2092 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2093 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2094 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2095 _("ckct_ib_unable_to_paste_here"));
2096 /* Notify the queue */
2097 modest_mail_operation_notify_end (self);
2101 /* Get source folder */
2102 iter = tny_list_create_iterator (headers);
2103 header = TNY_HEADER (tny_iterator_get_current (iter));
2104 src_folder = tny_header_get_folder (header);
2105 g_object_unref (header);
2106 g_object_unref (iter);
2108 /* Check folder source and destination */
2109 id1 = tny_folder_get_id (src_folder);
2110 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2111 same_folder = !g_ascii_strcasecmp (id1, id2);
2113 /* Set status failed and set an error */
2114 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2115 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2116 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2117 _("mcen_ib_unable_to_copy_samefolder"));
2119 /* Notify the queue */
2120 modest_mail_operation_notify_end (self);
2123 g_object_unref (src_folder);
2127 /* Create the helper */
2128 helper = g_slice_new0 (XFerMsgAsyncHelper);
2129 helper->mail_op = g_object_ref(self);
2130 helper->dest_folder = g_object_ref(folder);
2131 helper->headers = g_object_ref(headers);
2132 helper->user_callback = user_callback;
2133 helper->user_data = user_data;
2135 /* Get account and set it into mail_operation */
2136 priv->account = modest_tny_folder_get_account (src_folder);
2138 /* Transfer messages */
2139 tny_folder_transfer_msgs_async (src_folder,
2144 transfer_msgs_status_cb,
2150 on_refresh_folder (TnyFolder *folder,
2155 RefreshAsyncHelper *helper = NULL;
2156 ModestMailOperation *self = NULL;
2157 ModestMailOperationPrivate *priv = NULL;
2159 helper = (RefreshAsyncHelper *) user_data;
2160 self = helper->mail_op;
2161 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2164 priv->error = g_error_copy (*error);
2165 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2170 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2171 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2172 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2173 _("Error trying to refresh the contents of %s"),
2174 tny_folder_get_name (folder));
2178 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2181 /* Call user defined callback, if it exists */
2182 if (helper->user_callback) {
2183 gdk_threads_enter ();
2184 helper->user_callback (priv->source, folder, helper->user_data);
2185 gdk_threads_leave ();
2189 g_object_unref (helper->mail_op);
2190 g_slice_free (RefreshAsyncHelper, helper);
2191 g_object_unref (folder);
2193 /* Notify about operation end */
2194 modest_mail_operation_notify_end (self);
2198 on_refresh_folder_status_update (GObject *obj,
2202 RefreshAsyncHelper *helper = NULL;
2203 ModestMailOperation *self = NULL;
2204 ModestMailOperationPrivate *priv = NULL;
2205 ModestMailOperationState *state;
2207 g_return_if_fail (user_data != NULL);
2208 g_return_if_fail (status != NULL);
2209 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2211 helper = (RefreshAsyncHelper *) user_data;
2212 self = helper->mail_op;
2213 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2215 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2217 priv->done = status->position;
2218 priv->total = status->of_total;
2220 state = modest_mail_operation_clone_state (self);
2221 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2222 g_slice_free (ModestMailOperationState, state);
2226 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2228 RefreshAsyncUserCallback user_callback,
2231 ModestMailOperationPrivate *priv = NULL;
2232 RefreshAsyncHelper *helper = NULL;
2234 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2236 /* Pick a reference */
2237 g_object_ref (folder);
2239 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2241 /* Get account and set it into mail_operation */
2242 priv->account = modest_tny_folder_get_account (folder);
2244 /* Create the helper */
2245 helper = g_slice_new0 (RefreshAsyncHelper);
2246 helper->mail_op = g_object_ref(self);
2247 helper->user_callback = user_callback;
2248 helper->user_data = user_data;
2250 /* Refresh the folder. TODO: tinymail could issue a status
2251 updates before the callback call then this could happen. We
2252 must review the design */
2253 tny_folder_refresh_async (folder,
2255 on_refresh_folder_status_update,
2261 * It's used by the mail operation queue to notify the observers
2262 * attached to that signal that the operation finished. We need to use
2263 * that because tinymail does not give us the progress of a given
2264 * operation when it finishes (it directly calls the operation
2268 modest_mail_operation_notify_end (ModestMailOperation *self)
2270 ModestMailOperationState *state;
2271 ModestMailOperationPrivate *priv = NULL;
2273 g_return_if_fail (self);
2275 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2278 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
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);