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;
1649 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1650 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1651 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1652 _("Error trying to refresh the contents of %s"),
1653 tny_folder_get_name (folder));
1657 /* The mail operation might have been canceled in which case we do not
1658 want to notify anyone anymore. */
1659 if(priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1660 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1662 /* If user defined callback function was defined, call it */
1663 if (helper->user_callback) {
1664 /* This callback is called into an iddle by tinymail,
1665 and idles are not in the main lock */
1666 gdk_threads_enter ();
1667 helper->user_callback (self, helper->header, msg, helper->user_data);
1668 gdk_threads_leave ();
1674 g_object_unref (helper->header);
1675 g_slice_free (GetMsgAsyncHelper, helper);
1677 /* Notify about operation end */
1678 if(priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED)
1679 modest_mail_operation_notify_end (self);
1681 g_object_unref (G_OBJECT (self));
1685 get_msg_status_cb (GObject *obj,
1689 GetMsgAsyncHelper *helper = NULL;
1690 ModestMailOperation *self;
1691 ModestMailOperationPrivate *priv;
1692 ModestMailOperationState *state;
1694 g_return_if_fail (status != NULL);
1695 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1697 helper = (GetMsgAsyncHelper *) user_data;
1698 g_return_if_fail (helper != NULL);
1700 self = helper->mail_op;
1701 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1703 if(priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1709 state = modest_mail_operation_clone_state (self);
1710 state->bytes_done = status->position;
1711 state->bytes_total = status->of_total;
1712 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1713 g_slice_free (ModestMailOperationState, state);
1716 /****************************************************/
1718 ModestMailOperation *mail_op;
1720 GetMsgAsyncUserCallback user_callback;
1722 GDestroyNotify notify;
1726 GetMsgAsyncUserCallback user_callback;
1730 ModestMailOperation *mail_op;
1731 } NotifyGetMsgsInfo;
1735 * Used by get_msgs_full_thread to call the user_callback for each
1736 * message that has been read
1739 notify_get_msgs_full (gpointer data)
1741 NotifyGetMsgsInfo *info;
1743 info = (NotifyGetMsgsInfo *) data;
1745 /* Call the user callback. Idles are not in the main lock, so
1747 gdk_threads_enter ();
1748 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1749 gdk_threads_leave ();
1751 g_slice_free (NotifyGetMsgsInfo, info);
1757 * Used by get_msgs_full_thread to free al the thread resources and to
1758 * call the destroy function for the passed user_data
1761 get_msgs_full_destroyer (gpointer data)
1763 GetFullMsgsInfo *info;
1765 info = (GetFullMsgsInfo *) data;
1768 gdk_threads_enter ();
1769 info->notify (info->user_data);
1770 gdk_threads_leave ();
1774 g_object_unref (info->headers);
1775 g_slice_free (GetFullMsgsInfo, info);
1781 get_msgs_full_thread (gpointer thr_user_data)
1783 GetFullMsgsInfo *info;
1784 ModestMailOperationPrivate *priv = NULL;
1785 TnyIterator *iter = NULL;
1787 info = (GetFullMsgsInfo *) thr_user_data;
1788 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1790 iter = tny_list_create_iterator (info->headers);
1791 while (!tny_iterator_is_done (iter)) {
1795 header = TNY_HEADER (tny_iterator_get_current (iter));
1796 folder = tny_header_get_folder (header);
1798 /* Get message from folder */
1801 /* The callback will call it per each header */
1802 msg = tny_folder_get_msg (folder, header, &(priv->error));
1805 ModestMailOperationState *state;
1810 /* notify progress */
1811 state = modest_mail_operation_clone_state (info->mail_op);
1812 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1813 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1814 pair, (GDestroyNotify) modest_pair_free);
1816 /* The callback is the responsible for
1817 freeing the message */
1818 if (info->user_callback) {
1819 NotifyGetMsgsInfo *info_notify;
1820 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1821 info_notify->user_callback = info->user_callback;
1822 info_notify->mail_op = info->mail_op;
1823 info_notify->header = g_object_ref (header);
1824 info_notify->msg = g_object_ref (msg);
1825 info_notify->user_data = info->user_data;
1826 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1827 notify_get_msgs_full,
1830 g_object_unref (msg);
1833 /* Set status failed and set an error */
1834 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1835 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1836 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1837 "Error trying to get a message. No folder found for header");
1839 g_object_unref (header);
1840 tny_iterator_next (iter);
1843 /* Set operation status */
1844 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1845 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1847 /* Notify about operation end */
1848 g_idle_add (idle_notify_update_account_queue, g_object_ref (info->mail_op));
1850 /* Free thread resources. Will be called after all previous idles */
1851 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1857 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1858 TnyList *header_list,
1859 GetMsgAsyncUserCallback user_callback,
1861 GDestroyNotify notify)
1863 TnyHeader *header = NULL;
1864 TnyFolder *folder = NULL;
1866 ModestMailOperationPrivate *priv = NULL;
1867 GetFullMsgsInfo *info = NULL;
1868 gboolean size_ok = TRUE;
1870 TnyIterator *iter = NULL;
1872 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1874 /* Init mail operation */
1875 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1876 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1878 priv->total = tny_list_get_length(header_list);
1880 /* Get account and set it into mail_operation */
1881 if (tny_list_get_length (header_list) >= 1) {
1882 iter = tny_list_create_iterator (header_list);
1883 header = TNY_HEADER (tny_iterator_get_current (iter));
1884 folder = tny_header_get_folder (header);
1885 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1886 g_object_unref (header);
1887 g_object_unref (folder);
1889 if (tny_list_get_length (header_list) == 1) {
1890 g_object_unref (iter);
1895 /* Get msg size limit */
1896 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1897 MODEST_CONF_MSG_SIZE_LIMIT,
1900 g_clear_error (&(priv->error));
1901 max_size = G_MAXINT;
1903 max_size = max_size * KB;
1906 /* Check message size limits. If there is only one message
1907 always retrieve it */
1909 while (!tny_iterator_is_done (iter) && size_ok) {
1910 header = TNY_HEADER (tny_iterator_get_current (iter));
1911 if (tny_header_get_message_size (header) >= max_size)
1913 g_object_unref (header);
1914 tny_iterator_next (iter);
1916 g_object_unref (iter);
1920 /* Create the info */
1921 info = g_slice_new0 (GetFullMsgsInfo);
1922 info->mail_op = self;
1923 info->user_callback = user_callback;
1924 info->user_data = user_data;
1925 info->headers = g_object_ref (header_list);
1926 info->notify = notify;
1928 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1930 /* Set status failed and set an error */
1931 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1932 /* FIXME: the error msg is different for pop */
1933 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1934 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1935 _("emev_ni_ui_imap_msg_size_exceed_error"));
1936 /* Remove from queue and free resources */
1937 modest_mail_operation_notify_end (self);
1945 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
1946 gboolean remove_to_trash /*ignored*/)
1949 ModestMailOperationPrivate *priv;
1951 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1952 g_return_if_fail (TNY_IS_HEADER (header));
1954 if (remove_to_trash)
1955 g_warning ("remove to trash is not implemented");
1957 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1958 folder = tny_header_get_folder (header);
1960 /* Get account and set it into mail_operation */
1961 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1963 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1966 tny_folder_remove_msg (folder, header, &(priv->error));
1968 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
1970 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
1971 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
1972 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
1973 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
1976 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
1982 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1984 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1987 g_object_unref (G_OBJECT (folder));
1989 /* Notify about operation end */
1990 modest_mail_operation_notify_end (self);
1994 transfer_msgs_status_cb (GObject *obj,
1998 XFerMsgAsyncHelper *helper = NULL;
1999 ModestMailOperation *self;
2000 ModestMailOperationPrivate *priv;
2001 ModestMailOperationState *state;
2004 g_return_if_fail (status != NULL);
2005 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2007 helper = (XFerMsgAsyncHelper *) user_data;
2008 g_return_if_fail (helper != NULL);
2010 self = helper->mail_op;
2011 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2013 priv->done = status->position;
2014 priv->total = status->of_total;
2016 state = modest_mail_operation_clone_state (self);
2017 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2018 g_slice_free (ModestMailOperationState, state);
2023 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2025 XFerMsgAsyncHelper *helper;
2026 ModestMailOperation *self;
2027 ModestMailOperationPrivate *priv;
2029 helper = (XFerMsgAsyncHelper *) user_data;
2030 self = helper->mail_op;
2032 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2035 priv->error = g_error_copy (*err);
2037 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2038 } else if (cancelled) {
2039 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2040 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2041 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2042 _("Error trying to refresh the contents of %s"),
2043 tny_folder_get_name (folder));
2046 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2049 /* Notify about operation end */
2050 modest_mail_operation_notify_end (self);
2052 /* If user defined callback function was defined, call it */
2053 if (helper->user_callback) {
2054 gdk_threads_enter ();
2055 helper->user_callback (priv->source, helper->user_data);
2056 gdk_threads_leave ();
2060 g_object_unref (helper->headers);
2061 g_object_unref (helper->dest_folder);
2062 g_object_unref (helper->mail_op);
2063 g_slice_free (XFerMsgAsyncHelper, helper);
2064 g_object_unref (folder);
2069 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2072 gboolean delete_original,
2073 XferMsgsAsynUserCallback user_callback,
2076 ModestMailOperationPrivate *priv;
2078 TnyFolder *src_folder;
2079 XFerMsgAsyncHelper *helper;
2081 ModestTnyFolderRules rules;
2082 const gchar *id1 = NULL;
2083 const gchar *id2 = NULL;
2084 gboolean same_folder = FALSE;
2086 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2087 g_return_if_fail (TNY_IS_LIST (headers));
2088 g_return_if_fail (TNY_IS_FOLDER (folder));
2090 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2093 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2095 /* Apply folder rules */
2096 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2097 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2098 /* Set status failed and set an error */
2099 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2100 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2101 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2102 _("ckct_ib_unable_to_paste_here"));
2103 /* Notify the queue */
2104 modest_mail_operation_notify_end (self);
2108 /* Get source folder */
2109 iter = tny_list_create_iterator (headers);
2110 header = TNY_HEADER (tny_iterator_get_current (iter));
2111 src_folder = tny_header_get_folder (header);
2112 g_object_unref (header);
2113 g_object_unref (iter);
2115 /* Check folder source and destination */
2116 id1 = tny_folder_get_id (src_folder);
2117 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2118 same_folder = !g_ascii_strcasecmp (id1, id2);
2120 /* Set status failed and set an error */
2121 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2122 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2123 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2124 _("mcen_ib_unable_to_copy_samefolder"));
2126 /* Notify the queue */
2127 modest_mail_operation_notify_end (self);
2130 g_object_unref (src_folder);
2134 /* Create the helper */
2135 helper = g_slice_new0 (XFerMsgAsyncHelper);
2136 helper->mail_op = g_object_ref(self);
2137 helper->dest_folder = g_object_ref(folder);
2138 helper->headers = g_object_ref(headers);
2139 helper->user_callback = user_callback;
2140 helper->user_data = user_data;
2142 /* Get account and set it into mail_operation */
2143 priv->account = modest_tny_folder_get_account (src_folder);
2145 /* Transfer messages */
2146 tny_folder_transfer_msgs_async (src_folder,
2151 transfer_msgs_status_cb,
2157 on_refresh_folder (TnyFolder *folder,
2162 RefreshAsyncHelper *helper = NULL;
2163 ModestMailOperation *self = NULL;
2164 ModestMailOperationPrivate *priv = NULL;
2166 helper = (RefreshAsyncHelper *) user_data;
2167 self = helper->mail_op;
2168 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2171 priv->error = g_error_copy (*error);
2172 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2177 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2178 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2179 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2180 _("Error trying to refresh the contents of %s"),
2181 tny_folder_get_name (folder));
2185 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2188 /* Call user defined callback, if it exists */
2189 if (helper->user_callback) {
2190 gdk_threads_enter ();
2191 helper->user_callback (priv->source, folder, helper->user_data);
2192 gdk_threads_leave ();
2196 g_object_unref (helper->mail_op);
2197 g_slice_free (RefreshAsyncHelper, helper);
2198 g_object_unref (folder);
2200 /* Notify about operation end */
2201 modest_mail_operation_notify_end (self);
2205 on_refresh_folder_status_update (GObject *obj,
2209 RefreshAsyncHelper *helper = NULL;
2210 ModestMailOperation *self = NULL;
2211 ModestMailOperationPrivate *priv = NULL;
2212 ModestMailOperationState *state;
2214 g_return_if_fail (user_data != NULL);
2215 g_return_if_fail (status != NULL);
2216 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2218 helper = (RefreshAsyncHelper *) user_data;
2219 self = helper->mail_op;
2220 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2222 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2224 priv->done = status->position;
2225 priv->total = status->of_total;
2227 state = modest_mail_operation_clone_state (self);
2228 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2229 g_slice_free (ModestMailOperationState, state);
2233 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2235 RefreshAsyncUserCallback user_callback,
2238 ModestMailOperationPrivate *priv = NULL;
2239 RefreshAsyncHelper *helper = NULL;
2241 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2243 /* Pick a reference */
2244 g_object_ref (folder);
2246 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2248 /* Get account and set it into mail_operation */
2249 priv->account = modest_tny_folder_get_account (folder);
2251 /* Create the helper */
2252 helper = g_slice_new0 (RefreshAsyncHelper);
2253 helper->mail_op = g_object_ref(self);
2254 helper->user_callback = user_callback;
2255 helper->user_data = user_data;
2257 /* Refresh the folder. TODO: tinymail could issue a status
2258 updates before the callback call then this could happen. We
2259 must review the design */
2260 tny_folder_refresh_async (folder,
2262 on_refresh_folder_status_update,
2268 * It's used by the mail operation queue to notify the observers
2269 * attached to that signal that the operation finished. We need to use
2270 * that because tinymail does not give us the progress of a given
2271 * operation when it finishes (it directly calls the operation
2275 modest_mail_operation_notify_end (ModestMailOperation *self)
2277 ModestMailOperationState *state;
2278 ModestMailOperationPrivate *priv = NULL;
2280 g_return_if_fail (self);
2282 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2285 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
2289 /* Set the account back to not busy */
2290 if (priv->account_name) {
2291 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2292 priv->account_name, FALSE);
2293 g_free(priv->account_name);
2294 priv->account_name = NULL;
2297 /* Notify the observers about the mail opertation end */
2298 state = modest_mail_operation_clone_state (self);
2299 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2300 g_slice_free (ModestMailOperationState, state);