1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-camel-pop-store-account.h>
38 #include <tny-camel-pop-folder.h>
39 #include <tny-camel-imap-folder.h>
40 #include <tny-simple-list.h>
41 #include <tny-send-queue.h>
42 #include <tny-status.h>
43 #include <tny-folder-observer.h>
44 #include <camel/camel-stream-mem.h>
45 #include <glib/gi18n.h>
46 #include "modest-platform.h"
47 #include <modest-tny-account.h>
48 #include <modest-tny-send-queue.h>
49 #include <modest-runtime.h>
50 #include "modest-text-utils.h"
51 #include "modest-tny-msg.h"
52 #include "modest-tny-folder.h"
53 #include "modest-tny-platform-factory.h"
54 #include "modest-marshal.h"
55 #include "modest-error.h"
56 #include "modest-mail-operation.h"
60 /* 'private'/'protected' functions */
61 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
62 static void modest_mail_operation_init (ModestMailOperation *obj);
63 static void modest_mail_operation_finalize (GObject *obj);
65 static void get_msg_cb (TnyFolder *folder,
71 static void get_msg_status_cb (GObject *obj,
75 static void modest_mail_operation_notify_end (ModestMailOperation *self);
77 static gboolean did_a_cancel = FALSE;
79 enum _ModestMailOperationSignals
81 PROGRESS_CHANGED_SIGNAL,
86 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
87 struct _ModestMailOperationPrivate {
94 ErrorCheckingUserCallback error_checking;
95 gpointer error_checking_user_data;
96 ModestMailOperationStatus status;
97 ModestMailOperationTypeOperation op_type;
100 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
101 MODEST_TYPE_MAIL_OPERATION, \
102 ModestMailOperationPrivate))
104 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
105 priv->status = new_status;\
108 typedef struct _GetMsgAsyncHelper {
109 ModestMailOperation *mail_op;
111 GetMsgAsyncUserCallback user_callback;
115 typedef struct _RefreshAsyncHelper {
116 ModestMailOperation *mail_op;
117 RefreshAsyncUserCallback user_callback;
119 } RefreshAsyncHelper;
121 typedef struct _XFerMsgAsyncHelper
123 ModestMailOperation *mail_op;
125 TnyFolder *dest_folder;
126 XferMsgsAsynUserCallback user_callback;
128 } XFerMsgAsyncHelper;
131 static GObjectClass *parent_class = NULL;
133 static guint signals[NUM_SIGNALS] = {0};
136 modest_mail_operation_get_type (void)
138 static GType my_type = 0;
140 static const GTypeInfo my_info = {
141 sizeof(ModestMailOperationClass),
142 NULL, /* base init */
143 NULL, /* base finalize */
144 (GClassInitFunc) modest_mail_operation_class_init,
145 NULL, /* class finalize */
146 NULL, /* class data */
147 sizeof(ModestMailOperation),
149 (GInstanceInitFunc) modest_mail_operation_init,
152 my_type = g_type_register_static (G_TYPE_OBJECT,
153 "ModestMailOperation",
160 modest_mail_operation_class_init (ModestMailOperationClass *klass)
162 GObjectClass *gobject_class;
163 gobject_class = (GObjectClass*) klass;
165 parent_class = g_type_class_peek_parent (klass);
166 gobject_class->finalize = modest_mail_operation_finalize;
168 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
171 * ModestMailOperation::progress-changed
172 * @self: the #MailOperation that emits the signal
173 * @user_data: user data set when the signal handler was connected
175 * Emitted when the progress of a mail operation changes
177 signals[PROGRESS_CHANGED_SIGNAL] =
178 g_signal_new ("progress-changed",
179 G_TYPE_FROM_CLASS (gobject_class),
181 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
183 g_cclosure_marshal_VOID__POINTER,
184 G_TYPE_NONE, 1, G_TYPE_POINTER);
189 modest_mail_operation_init (ModestMailOperation *obj)
191 ModestMailOperationPrivate *priv;
193 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
195 priv->account = NULL;
196 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
197 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
202 priv->error_checking = NULL;
203 priv->error_checking_user_data = NULL;
207 modest_mail_operation_finalize (GObject *obj)
209 ModestMailOperationPrivate *priv;
211 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
216 g_error_free (priv->error);
220 g_object_unref (priv->source);
224 g_object_unref (priv->account);
225 priv->account = NULL;
229 G_OBJECT_CLASS(parent_class)->finalize (obj);
233 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
236 ModestMailOperation *obj;
237 ModestMailOperationPrivate *priv;
239 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
240 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
242 priv->op_type = op_type;
244 priv->source = g_object_ref(source);
250 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
252 ErrorCheckingUserCallback error_handler,
255 ModestMailOperation *obj;
256 ModestMailOperationPrivate *priv;
258 obj = modest_mail_operation_new (op_type, source);
259 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
261 g_return_val_if_fail (error_handler != NULL, obj);
262 priv->error_checking = error_handler;
268 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
270 ModestMailOperationPrivate *priv;
272 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
273 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
275 if (priv->error_checking != NULL)
276 priv->error_checking (self, priv->error_checking_user_data);
280 ModestMailOperationTypeOperation
281 modest_mail_operation_get_type_operation (ModestMailOperation *self)
283 ModestMailOperationPrivate *priv;
285 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
287 return priv->op_type;
291 modest_mail_operation_is_mine (ModestMailOperation *self,
294 ModestMailOperationPrivate *priv;
296 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
297 if (priv->source == NULL) return FALSE;
299 return priv->source == me;
303 modest_mail_operation_get_source (ModestMailOperation *self)
305 ModestMailOperationPrivate *priv;
307 g_return_val_if_fail (self, NULL);
309 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
311 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
315 return g_object_ref (priv->source);
318 ModestMailOperationStatus
319 modest_mail_operation_get_status (ModestMailOperation *self)
321 ModestMailOperationPrivate *priv;
323 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
324 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
325 MODEST_MAIL_OPERATION_STATUS_INVALID);
327 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
329 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
330 return MODEST_MAIL_OPERATION_STATUS_INVALID;
337 modest_mail_operation_get_error (ModestMailOperation *self)
339 ModestMailOperationPrivate *priv;
341 g_return_val_if_fail (self, NULL);
342 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
344 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
347 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
355 modest_mail_operation_cancel (ModestMailOperation *self)
357 ModestMailOperationPrivate *priv;
359 if (!MODEST_IS_MAIL_OPERATION (self)) {
360 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
364 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
366 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
373 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
375 /* This emits progress-changed on which the mail operation queue is
376 * listening, so the mail operation is correctly removed from the
377 * queue without further explicit calls. */
378 modest_mail_operation_notify_end (self);
384 modest_mail_operation_get_task_done (ModestMailOperation *self)
386 ModestMailOperationPrivate *priv;
388 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
390 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
395 modest_mail_operation_get_task_total (ModestMailOperation *self)
397 ModestMailOperationPrivate *priv;
399 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
401 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
406 modest_mail_operation_is_finished (ModestMailOperation *self)
408 ModestMailOperationPrivate *priv;
409 gboolean retval = FALSE;
411 if (!MODEST_IS_MAIL_OPERATION (self)) {
412 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
416 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
418 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
419 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
420 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
421 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
431 modest_mail_operation_get_id (ModestMailOperation *self)
433 ModestMailOperationPrivate *priv;
435 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
437 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
442 modest_mail_operation_set_id (ModestMailOperation *self,
445 ModestMailOperationPrivate *priv;
447 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
449 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
454 * Creates an image of the current state of a mail operation, the
455 * caller must free it
457 static ModestMailOperationState *
458 modest_mail_operation_clone_state (ModestMailOperation *self)
460 ModestMailOperationState *state;
461 ModestMailOperationPrivate *priv;
463 /* FIXME: this should be fixed properly
465 * in some cases, priv was NULL, so checking here to
468 g_return_val_if_fail (self, NULL);
469 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
470 g_return_val_if_fail (priv, NULL);
475 state = g_slice_new (ModestMailOperationState);
477 state->status = priv->status;
478 state->op_type = priv->op_type;
479 state->done = priv->done;
480 state->total = priv->total;
481 state->finished = modest_mail_operation_is_finished (self);
482 state->bytes_done = 0;
483 state->bytes_total = 0;
488 /* ******************************************************************* */
489 /* ************************** SEND ACTIONS ************************* */
490 /* ******************************************************************* */
493 modest_mail_operation_send_mail (ModestMailOperation *self,
494 TnyTransportAccount *transport_account,
497 TnySendQueue *send_queue = NULL;
498 ModestMailOperationPrivate *priv;
500 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
501 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
502 g_return_if_fail (TNY_IS_MSG (msg));
504 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
506 /* Get account and set it into mail_operation */
507 priv->account = g_object_ref (transport_account);
511 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
512 if (!TNY_IS_SEND_QUEUE(send_queue)) {
513 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
514 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
515 "modest: could not find send queue for account\n");
517 /* TODO: connect to the msg-sent in order to know when
518 the mail operation is finished */
519 tny_send_queue_add (send_queue, msg, &(priv->error));
520 /* TODO: we're setting always success, do the check in
522 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
525 /* TODO: do this in the handler of the "msg-sent"
526 signal.Notify about operation end */
527 modest_mail_operation_notify_end (self);
531 modest_mail_operation_send_new_mail (ModestMailOperation *self,
532 TnyTransportAccount *transport_account,
534 const gchar *from, const gchar *to,
535 const gchar *cc, const gchar *bcc,
536 const gchar *subject, const gchar *plain_body,
537 const gchar *html_body,
538 const GList *attachments_list,
539 TnyHeaderFlags priority_flags)
541 TnyMsg *new_msg = NULL;
542 TnyFolder *folder = NULL;
543 TnyHeader *header = NULL;
544 ModestMailOperationPrivate *priv = NULL;
546 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
547 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
549 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
551 /* Check parametters */
553 /* Set status failed and set an error */
554 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
555 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
556 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
557 _("Error trying to send a mail. You need to set at least one recipient"));
561 if (html_body == NULL) {
562 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
564 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
567 g_printerr ("modest: failed to create a new msg\n");
571 /* Set priority flags in message */
572 header = tny_msg_get_header (new_msg);
573 if (priority_flags != 0)
574 tny_header_set_flags (header, priority_flags);
575 if (attachments_list != NULL) {
576 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
578 g_object_unref (G_OBJECT(header));
580 /* Call mail operation */
581 modest_mail_operation_send_mail (self, transport_account, new_msg);
583 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
585 if (draft_msg != NULL) {
586 header = tny_msg_get_header (draft_msg);
587 /* Note: This can fail (with a warning) if the message is not really already in a folder,
588 * because this function requires it to have a UID. */
589 tny_folder_remove_msg (folder, header, NULL);
590 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
591 g_object_unref (header);
596 g_object_unref (G_OBJECT (new_msg));
600 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
601 TnyTransportAccount *transport_account,
603 const gchar *from, const gchar *to,
604 const gchar *cc, const gchar *bcc,
605 const gchar *subject, const gchar *plain_body,
606 const gchar *html_body,
607 const GList *attachments_list,
608 TnyHeaderFlags priority_flags)
611 TnyFolder *folder = NULL;
612 TnyHeader *header = NULL;
613 ModestMailOperationPrivate *priv = NULL;
615 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
616 g_return_val_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account), NULL);
618 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
620 /* Get account and set it into mail_operation */
621 priv->account = g_object_ref (transport_account);
623 if (html_body == NULL) {
624 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
626 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
629 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
630 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
631 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
632 "modest: failed to create a new msg\n");
636 /* add priority flags */
637 header = tny_msg_get_header (msg);
638 tny_header_set_flags (header, priority_flags);
639 if (attachments_list != NULL)
640 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
641 g_object_unref (G_OBJECT(header));
643 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
645 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
646 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
647 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
648 "modest: failed to create a new msg\n");
652 if (draft_msg != NULL) {
653 header = tny_msg_get_header (draft_msg);
654 /* Remove the old draft expunging it */
655 tny_folder_remove_msg (folder, header, NULL);
656 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
657 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
658 g_object_unref (header);
662 tny_folder_add_msg (folder, msg, &(priv->error));
665 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
667 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
671 g_object_unref (G_OBJECT(folder));
673 modest_mail_operation_notify_end (self);
679 ModestMailOperation *mail_op;
680 TnyStoreAccount *account;
681 TnyTransportAccount *transport_account;
684 gchar *retrieve_type;
686 UpdateAccountCallback callback;
691 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
692 /* We use this folder observer to track the headers that have been
693 * added to a folder */
696 TnyList *new_headers;
697 } InternalFolderObserver;
701 } InternalFolderObserverClass;
703 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
705 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
706 internal_folder_observer,
708 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
712 foreach_add_item (gpointer header, gpointer user_data)
714 /* printf("DEBUG: %s: header subject=%s\n",
715 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
717 tny_list_prepend (TNY_LIST (user_data),
718 g_object_ref (G_OBJECT (header)));
721 /* This is the method that looks for new messages in a folder */
723 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
725 InternalFolderObserver *derived = (InternalFolderObserver *)self;
727 TnyFolderChangeChanged changed;
729 changed = tny_folder_change_get_changed (change);
731 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
734 /* Get added headers */
735 list = tny_simple_list_new ();
736 tny_folder_change_get_added_headers (change, list);
738 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
739 * __FUNCTION__, tny_list_get_length(list));
742 /* Add them to the folder observer */
743 tny_list_foreach (list, foreach_add_item,
744 derived->new_headers);
746 g_object_unref (G_OBJECT (list));
751 internal_folder_observer_init (InternalFolderObserver *self)
753 self->new_headers = tny_simple_list_new ();
756 internal_folder_observer_finalize (GObject *object)
758 InternalFolderObserver *self;
760 self = (InternalFolderObserver *) object;
761 g_object_unref (self->new_headers);
763 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
766 tny_folder_observer_init (TnyFolderObserverIface *iface)
768 iface->update_func = internal_folder_observer_update;
771 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
773 GObjectClass *object_class;
775 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
776 object_class = (GObjectClass*) klass;
777 object_class->finalize = internal_folder_observer_finalize;
783 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
786 TnyList *folders = tny_simple_list_new ();
788 tny_folder_store_get_folders (store, folders, query, NULL);
789 iter = tny_list_create_iterator (folders);
791 while (!tny_iterator_is_done (iter)) {
793 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
795 tny_list_prepend (all_folders, G_OBJECT (folder));
796 recurse_folders (folder, query, all_folders);
797 g_object_unref (G_OBJECT (folder));
799 tny_iterator_next (iter);
801 g_object_unref (G_OBJECT (iter));
802 g_object_unref (G_OBJECT (folders));
806 * Issues the "progress-changed" signal. The timer won't be removed,
807 * so you must call g_source_remove to stop the signal emission
810 idle_notify_progress (gpointer data)
812 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
813 ModestMailOperationState *state;
815 state = modest_mail_operation_clone_state (mail_op);
816 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
817 g_slice_free (ModestMailOperationState, state);
823 * Issues the "progress-changed" signal and removes the timer. It uses
824 * a lock to ensure that the progress information of the mail
825 * operation is not modified while there are notifications pending
828 idle_notify_progress_once (gpointer data)
832 pair = (ModestPair *) data;
834 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
836 /* Free the state and the reference to the mail operation */
837 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
838 g_object_unref (pair->first);
844 * Used by update_account_thread to notify the queue from the main
845 * loop. We call it inside an idle call to achieve that
848 idle_notify_update_account_queue (gpointer data)
850 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
851 ModestMailOperationPrivate *priv = NULL;
853 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
855 /* Do not need to block, the notify end will do it for us */
856 modest_mail_operation_notify_end (mail_op);
857 g_object_unref (mail_op);
863 compare_headers_by_date (gconstpointer a,
866 TnyHeader **header1, **header2;
869 header1 = (TnyHeader **) a;
870 header2 = (TnyHeader **) b;
872 sent1 = tny_header_get_date_sent (*header1);
873 sent2 = tny_header_get_date_sent (*header2);
875 /* We want the most recent ones (greater time_t) at the
884 set_last_updated_idle (gpointer data)
886 gdk_threads_enter ();
888 /* It does not matter if the time is not exactly the same than
889 the time when this idle was called, it's just an
890 approximation and it won't be very different */
891 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
893 MODEST_ACCOUNT_LAST_UPDATED,
897 gdk_threads_leave ();
903 idle_update_account_cb (gpointer data)
905 UpdateAccountInfo *idle_info;
907 idle_info = (UpdateAccountInfo *) data;
909 gdk_threads_enter ();
910 idle_info->callback (idle_info->mail_op,
911 idle_info->new_headers,
912 idle_info->user_data);
913 gdk_threads_leave ();
916 g_object_unref (idle_info->mail_op);
924 update_account_thread (gpointer thr_user_data)
926 static gboolean first_time = TRUE;
927 UpdateAccountInfo *info;
928 TnyList *all_folders = NULL;
929 GPtrArray *new_headers = NULL;
930 TnyIterator *iter = NULL;
931 TnyFolderStoreQuery *query = NULL;
932 ModestMailOperationPrivate *priv = NULL;
933 ModestTnySendQueue *send_queue = NULL;
935 info = (UpdateAccountInfo *) thr_user_data;
936 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
938 /* Get account and set it into mail_operation */
939 priv->account = g_object_ref (info->account);
942 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
943 * show any updates unless we do that
945 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
946 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
948 /* Get all the folders. We can do it synchronously because
949 we're already running in a different thread than the UI */
950 all_folders = tny_simple_list_new ();
951 query = tny_folder_store_query_new ();
952 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
953 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
958 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
962 iter = tny_list_create_iterator (all_folders);
963 while (!tny_iterator_is_done (iter)) {
964 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
966 recurse_folders (folder, query, all_folders);
967 tny_iterator_next (iter);
969 g_object_unref (G_OBJECT (iter));
971 /* Update status and notify. We need to call the notification
972 with a source function in order to call it from the main
973 loop. We need that in order not to get into trouble with
974 Gtk+. We use a timeout in order to provide more status
975 information, because the sync tinymail call does not
976 provide it for the moment */
977 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
979 /* Refresh folders */
980 new_headers = g_ptr_array_new ();
981 iter = tny_list_create_iterator (all_folders);
983 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
985 InternalFolderObserver *observer;
986 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
988 /* Refresh the folder */
989 /* Our observer receives notification of new emails during folder refreshes,
990 * so we can use observer->new_headers.
992 observer = g_object_new (internal_folder_observer_get_type (), NULL);
993 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
995 /* This gets the status information (headers) from the server.
996 * We use the blocking version, because we are already in a separate
1000 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1001 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1004 /* If the retrieve type is full messages, refresh and get the messages */
1005 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1007 iter = tny_list_create_iterator (observer->new_headers);
1008 while (!tny_iterator_is_done (iter)) {
1009 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1011 /* Apply per-message size limits */
1012 if (tny_header_get_message_size (header) < info->max_size)
1013 g_ptr_array_add (new_headers, g_object_ref (header));
1015 g_object_unref (header);
1016 tny_iterator_next (iter);
1018 g_object_unref (iter);
1020 /* We do not need to do it the first time
1021 because it's automatically done by the tree
1023 if (G_UNLIKELY (!first_time))
1024 tny_folder_poke_status (TNY_FOLDER (folder));
1026 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1027 g_object_unref (observer);
1030 g_object_unref (G_OBJECT (folder));
1033 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1037 tny_iterator_next (iter);
1040 did_a_cancel = FALSE;
1042 g_object_unref (G_OBJECT (iter));
1043 g_source_remove (timeout);
1045 if (new_headers->len > 0) {
1049 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1051 /* Apply message count limit */
1052 /* If the number of messages exceeds the maximum, ask the
1053 * user to download them all,
1054 * as per the UI spec "Retrieval Limits" section in 4.4:
1056 if (new_headers->len > info->retrieve_limit) {
1057 /* TODO: Ask the user, instead of just
1059 * mail_nc_msg_count_limit_exceeded, with 'Get
1060 * all' and 'Newest only' buttons. */
1061 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1062 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1063 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1064 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1065 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1070 priv->total = MIN (new_headers->len, info->retrieve_limit);
1071 while (msg_num < priv->total) {
1073 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1074 TnyFolder *folder = tny_header_get_folder (header);
1075 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1076 ModestMailOperationState *state;
1080 /* We can not just use the mail operation because the
1081 values of done and total could change before the
1083 state = modest_mail_operation_clone_state (info->mail_op);
1084 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1085 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1086 pair, (GDestroyNotify) modest_pair_free);
1088 g_object_unref (msg);
1089 g_object_unref (folder);
1093 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1094 g_ptr_array_free (new_headers, FALSE);
1098 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1101 if (priv->account != NULL)
1102 g_object_unref (priv->account);
1103 priv->account = g_object_ref (info->transport_account);
1105 send_queue = modest_runtime_get_send_queue (info->transport_account);
1107 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
1108 modest_tny_send_queue_try_to_send (send_queue);
1109 g_source_remove (timeout);
1111 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1112 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1113 "cannot create a send queue for %s\n",
1114 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1115 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1118 /* Check if the operation was a success */
1120 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1122 /* Update the last updated key */
1123 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1124 set_last_updated_idle,
1125 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1126 (GDestroyNotify) g_free);
1131 if (info->callback) {
1132 UpdateAccountInfo *idle_info;
1134 /* This thread is not in the main lock */
1135 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1136 idle_info->mail_op = g_object_ref (info->mail_op);
1137 idle_info->new_headers = (new_headers) ? new_headers->len : 0;
1138 idle_info->callback = info->callback;
1139 g_idle_add (idle_update_account_cb, idle_info);
1142 /* Notify about operation end. Note that the info could be
1143 freed before this idle happens, but the mail operation will
1145 g_idle_add (idle_notify_update_account_queue, g_object_ref (info->mail_op));
1148 g_object_unref (query);
1149 g_object_unref (all_folders);
1150 g_object_unref (info->account);
1151 g_object_unref (info->transport_account);
1152 g_free (info->retrieve_type);
1153 g_slice_free (UpdateAccountInfo, info);
1161 modest_mail_operation_update_account (ModestMailOperation *self,
1162 const gchar *account_name,
1163 UpdateAccountCallback callback,
1167 UpdateAccountInfo *info;
1168 ModestMailOperationPrivate *priv;
1169 ModestAccountMgr *mgr;
1170 TnyStoreAccount *modest_account;
1171 TnyTransportAccount *transport_account;
1173 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1174 g_return_val_if_fail (account_name, FALSE);
1176 /* Init mail operation. Set total and done to 0, and do not
1177 update them, this way the progress objects will know that
1178 we have no clue about the number of the objects */
1179 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1182 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1184 /* Make sure that we have a connection, and request one
1186 * TODO: Is there some way to trigger this for every attempt to
1187 * use the network? */
1188 if (!modest_platform_connect_and_wait (NULL))
1191 /* Get the Modest account */
1192 modest_account = (TnyStoreAccount *)
1193 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1195 TNY_ACCOUNT_TYPE_STORE);
1197 if (!modest_account) {
1198 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1199 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1200 "cannot get tny store account for %s\n", account_name);
1205 /* Get the transport account, we can not do it in the thread
1206 due to some problems with dbus */
1207 transport_account = (TnyTransportAccount *)
1208 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1210 if (!transport_account) {
1211 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1212 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1213 "cannot get tny transport account for %s\n", account_name);
1217 /* Create the helper object */
1218 info = g_slice_new (UpdateAccountInfo);
1219 info->mail_op = self;
1220 info->account = modest_account;
1221 info->transport_account = transport_account;
1222 info->callback = callback;
1223 info->user_data = user_data;
1225 /* Get the message size limit */
1226 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1227 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1228 if (info->max_size == 0)
1229 info->max_size = G_MAXINT;
1231 info->max_size = info->max_size * KB;
1233 /* Get per-account retrieval type */
1234 mgr = modest_runtime_get_account_mgr ();
1235 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1236 MODEST_ACCOUNT_RETRIEVE, FALSE);
1238 /* Get per-account message amount retrieval limit */
1239 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1240 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1241 if (info->retrieve_limit == 0)
1242 info->retrieve_limit = G_MAXINT;
1244 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1246 /* Set account busy */
1247 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1248 priv->account_name = g_strdup(account_name);
1250 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1255 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1257 callback (self, 0, user_data);
1258 modest_mail_operation_notify_end (self);
1262 /* ******************************************************************* */
1263 /* ************************** STORE ACTIONS ************************* */
1264 /* ******************************************************************* */
1268 modest_mail_operation_create_folder (ModestMailOperation *self,
1269 TnyFolderStore *parent,
1272 ModestMailOperationPrivate *priv;
1273 TnyFolder *new_folder = NULL;
1275 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1276 g_return_val_if_fail (name, NULL);
1278 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1281 if (TNY_IS_FOLDER (parent)) {
1282 /* Check folder rules */
1283 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1284 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1285 /* Set status failed and set an error */
1286 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1287 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1288 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1289 _("mail_in_ui_folder_create_error"));
1293 if (!strcmp (name, " ") || strchr (name, '/')) {
1294 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1295 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1296 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1297 _("mail_in_ui_folder_create_error"));
1301 /* Create the folder */
1302 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1303 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1305 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1308 /* Notify about operation end */
1309 modest_mail_operation_notify_end (self);
1315 modest_mail_operation_remove_folder (ModestMailOperation *self,
1317 gboolean remove_to_trash)
1319 TnyAccount *account;
1320 ModestMailOperationPrivate *priv;
1321 ModestTnyFolderRules rules;
1323 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1324 g_return_if_fail (TNY_IS_FOLDER (folder));
1326 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1328 /* Check folder rules */
1329 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1330 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1331 /* Set status failed and set an error */
1332 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1333 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1334 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1335 _("mail_in_ui_folder_delete_error"));
1339 /* Get the account */
1340 account = modest_tny_folder_get_account (folder);
1341 priv->account = g_object_ref(account);
1343 /* Delete folder or move to trash */
1344 if (remove_to_trash) {
1345 TnyFolder *trash_folder = NULL;
1346 trash_folder = modest_tny_account_get_special_folder (account,
1347 TNY_FOLDER_TYPE_TRASH);
1348 /* TODO: error_handling */
1349 modest_mail_operation_xfer_folder (self, folder,
1350 TNY_FOLDER_STORE (trash_folder),
1353 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1355 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1356 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1359 g_object_unref (G_OBJECT (parent));
1361 g_object_unref (G_OBJECT (account));
1364 /* Notify about operation end */
1365 modest_mail_operation_notify_end (self);
1369 transfer_folder_status_cb (GObject *obj,
1373 ModestMailOperation *self;
1374 ModestMailOperationPrivate *priv;
1375 ModestMailOperationState *state;
1376 XFerMsgAsyncHelper *helper;
1378 g_return_if_fail (status != NULL);
1379 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1381 helper = (XFerMsgAsyncHelper *) user_data;
1382 g_return_if_fail (helper != NULL);
1384 self = helper->mail_op;
1385 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1387 priv->done = status->position;
1388 priv->total = status->of_total;
1390 state = modest_mail_operation_clone_state (self);
1391 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1392 g_slice_free (ModestMailOperationState, state);
1397 transfer_folder_cb (TnyFolder *folder,
1398 TnyFolderStore *into,
1400 TnyFolder *new_folder,
1404 XFerMsgAsyncHelper *helper;
1405 ModestMailOperation *self = NULL;
1406 ModestMailOperationPrivate *priv = NULL;
1408 helper = (XFerMsgAsyncHelper *) user_data;
1409 g_return_if_fail (helper != NULL);
1411 self = helper->mail_op;
1412 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1415 priv->error = g_error_copy (*err);
1417 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1418 } else if (cancelled) {
1419 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1420 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1421 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1422 _("Transference of %s was cancelled."),
1423 tny_folder_get_name (folder));
1426 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1429 /* Notify about operation end */
1430 modest_mail_operation_notify_end (self);
1432 /* If user defined callback function was defined, call it */
1433 if (helper->user_callback) {
1434 gdk_threads_enter ();
1435 helper->user_callback (priv->source, helper->user_data);
1436 gdk_threads_leave ();
1440 g_object_unref (helper->mail_op);
1441 g_slice_free (XFerMsgAsyncHelper, helper);
1442 g_object_unref (folder);
1443 g_object_unref (into);
1447 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1449 TnyFolderStore *parent,
1450 gboolean delete_original,
1451 XferMsgsAsynUserCallback user_callback,
1454 ModestMailOperationPrivate *priv = NULL;
1455 ModestTnyFolderRules parent_rules = 0, rules;
1456 XFerMsgAsyncHelper *helper = NULL;
1458 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1459 g_return_if_fail (TNY_IS_FOLDER (folder));
1461 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1463 /* Get account and set it into mail_operation */
1464 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1465 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1467 /* Get folder rules */
1468 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1469 if (TNY_IS_FOLDER (parent))
1470 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1472 /* The moveable restriction is applied also to copy operation */
1473 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1474 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1475 /* Set status failed and set an error */
1476 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1477 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1478 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1479 _("mail_in_ui_folder_move_target_error"));
1481 /* Notify the queue */
1482 modest_mail_operation_notify_end (self);
1483 } else if (TNY_IS_FOLDER (parent) &&
1484 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1485 /* Set status failed and set an error */
1486 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1487 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1488 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1489 _("FIXME: parent folder does not accept new folders"));
1491 /* Notify the queue */
1492 modest_mail_operation_notify_end (self);
1494 /* Pick references for async calls */
1495 g_object_ref (folder);
1496 g_object_ref (parent);
1498 /* Create the helper */
1499 helper = g_slice_new0 (XFerMsgAsyncHelper);
1500 helper->mail_op = g_object_ref(self);
1501 helper->dest_folder = NULL;
1502 helper->headers = NULL;
1503 helper->user_callback = user_callback;
1504 helper->user_data = user_data;
1506 /* Move/Copy folder */
1507 tny_folder_copy_async (folder,
1509 tny_folder_get_name (folder),
1512 transfer_folder_status_cb,
1519 modest_mail_operation_rename_folder (ModestMailOperation *self,
1523 ModestMailOperationPrivate *priv;
1524 ModestTnyFolderRules rules;
1525 XFerMsgAsyncHelper *helper;
1527 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1528 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1529 g_return_if_fail (name);
1531 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1533 /* Get account and set it into mail_operation */
1534 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1536 /* Check folder rules */
1537 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1538 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1539 /* Set status failed and set an error */
1540 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1541 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1542 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1543 _("FIXME: unable to rename"));
1545 /* Notify about operation end */
1546 modest_mail_operation_notify_end (self);
1547 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1548 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1549 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1550 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1551 _("FIXME: unable to rename"));
1552 /* Notify about operation end */
1553 modest_mail_operation_notify_end (self);
1555 TnyFolderStore *into;
1557 /* Create the helper */
1558 helper = g_slice_new0 (XFerMsgAsyncHelper);
1559 helper->mail_op = g_object_ref(self);
1560 helper->dest_folder = NULL;
1561 helper->headers = NULL;
1562 helper->user_callback = NULL;
1563 helper->user_data = NULL;
1565 /* Rename. Camel handles folder subscription/unsubscription */
1566 into = tny_folder_get_folder_store (folder);
1567 tny_folder_copy_async (folder, into, name, TRUE,
1569 transfer_folder_status_cb,
1573 g_object_unref (into);
1577 /* ******************************************************************* */
1578 /* ************************** MSG ACTIONS ************************* */
1579 /* ******************************************************************* */
1581 void modest_mail_operation_get_msg (ModestMailOperation *self,
1583 GetMsgAsyncUserCallback user_callback,
1586 GetMsgAsyncHelper *helper = NULL;
1588 ModestMailOperationPrivate *priv;
1590 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1591 g_return_if_fail (TNY_IS_HEADER (header));
1593 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1594 folder = tny_header_get_folder (header);
1596 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1598 /* Get message from folder */
1600 /* Get account and set it into mail_operation */
1601 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1603 helper = g_slice_new0 (GetMsgAsyncHelper);
1604 helper->mail_op = self;
1605 helper->user_callback = user_callback;
1606 helper->user_data = user_data;
1607 helper->header = g_object_ref (header);
1609 // The callback's reference so that the mail op is not
1610 // finalized until the async operation is completed even if
1611 // the user canceled the request meanwhile.
1612 g_object_ref (G_OBJECT (helper->mail_op));
1614 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1616 g_object_unref (G_OBJECT (folder));
1618 /* Set status failed and set an error */
1619 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1620 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1621 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1622 _("Error trying to get a message. No folder found for header"));
1624 /* Notify the queue */
1625 modest_mail_operation_notify_end (self);
1630 get_msg_cb (TnyFolder *folder,
1636 GetMsgAsyncHelper *helper = NULL;
1637 ModestMailOperation *self = NULL;
1638 ModestMailOperationPrivate *priv = NULL;
1640 helper = (GetMsgAsyncHelper *) user_data;
1641 g_return_if_fail (helper != NULL);
1642 self = helper->mail_op;
1643 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1644 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1646 /* Check errors and cancel */
1648 priv->error = g_error_copy (*error);
1649 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1650 } else if (cancelled) {
1651 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1652 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1653 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1654 _("Error trying to refresh the contents of %s"),
1655 tny_folder_get_name (folder));
1657 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1660 /* If user defined callback function was defined, call it even
1661 if the operation failed*/
1662 if (helper->user_callback) {
1663 /* This callback is called into an iddle by tinymail,
1664 and idles are not in the main lock */
1665 gdk_threads_enter ();
1666 helper->user_callback (self, helper->header, msg, helper->user_data);
1667 gdk_threads_leave ();
1671 g_object_unref (helper->mail_op);
1672 g_object_unref (helper->header);
1673 g_slice_free (GetMsgAsyncHelper, helper);
1675 /* Notify about operation end */
1676 modest_mail_operation_notify_end (self);
1680 get_msg_status_cb (GObject *obj,
1684 GetMsgAsyncHelper *helper = NULL;
1685 ModestMailOperation *self;
1686 ModestMailOperationPrivate *priv;
1687 ModestMailOperationState *state;
1689 g_return_if_fail (status != NULL);
1690 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1692 helper = (GetMsgAsyncHelper *) user_data;
1693 g_return_if_fail (helper != NULL);
1695 self = helper->mail_op;
1696 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1698 if(priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1704 state = modest_mail_operation_clone_state (self);
1705 state->bytes_done = status->position;
1706 state->bytes_total = status->of_total;
1707 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1708 g_slice_free (ModestMailOperationState, state);
1711 /****************************************************/
1713 ModestMailOperation *mail_op;
1715 GetMsgAsyncUserCallback user_callback;
1717 GDestroyNotify notify;
1721 GetMsgAsyncUserCallback user_callback;
1725 ModestMailOperation *mail_op;
1726 } NotifyGetMsgsInfo;
1730 * Used by get_msgs_full_thread to call the user_callback for each
1731 * message that has been read
1734 notify_get_msgs_full (gpointer data)
1736 NotifyGetMsgsInfo *info;
1738 info = (NotifyGetMsgsInfo *) data;
1740 /* Call the user callback. Idles are not in the main lock, so
1742 gdk_threads_enter ();
1743 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1744 gdk_threads_leave ();
1746 g_slice_free (NotifyGetMsgsInfo, info);
1752 * Used by get_msgs_full_thread to free al the thread resources and to
1753 * call the destroy function for the passed user_data
1756 get_msgs_full_destroyer (gpointer data)
1758 GetFullMsgsInfo *info;
1760 info = (GetFullMsgsInfo *) data;
1763 gdk_threads_enter ();
1764 info->notify (info->user_data);
1765 gdk_threads_leave ();
1769 g_object_unref (info->headers);
1770 g_slice_free (GetFullMsgsInfo, info);
1776 get_msgs_full_thread (gpointer thr_user_data)
1778 GetFullMsgsInfo *info;
1779 ModestMailOperationPrivate *priv = NULL;
1780 TnyIterator *iter = NULL;
1782 info = (GetFullMsgsInfo *) thr_user_data;
1783 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1785 iter = tny_list_create_iterator (info->headers);
1786 while (!tny_iterator_is_done (iter)) {
1790 header = TNY_HEADER (tny_iterator_get_current (iter));
1791 folder = tny_header_get_folder (header);
1793 /* Get message from folder */
1796 /* The callback will call it per each header */
1797 msg = tny_folder_get_msg (folder, header, &(priv->error));
1800 ModestMailOperationState *state;
1805 /* notify progress */
1806 state = modest_mail_operation_clone_state (info->mail_op);
1807 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1808 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1809 pair, (GDestroyNotify) modest_pair_free);
1811 /* The callback is the responsible for
1812 freeing the message */
1813 if (info->user_callback) {
1814 NotifyGetMsgsInfo *info_notify;
1815 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1816 info_notify->user_callback = info->user_callback;
1817 info_notify->mail_op = info->mail_op;
1818 info_notify->header = g_object_ref (header);
1819 info_notify->msg = g_object_ref (msg);
1820 info_notify->user_data = info->user_data;
1821 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1822 notify_get_msgs_full,
1825 g_object_unref (msg);
1828 /* Set status failed and set an error */
1829 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1830 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1831 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1832 "Error trying to get a message. No folder found for header");
1834 g_object_unref (header);
1835 tny_iterator_next (iter);
1838 /* Set operation status */
1839 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1840 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1842 /* Notify about operation end */
1843 g_idle_add (idle_notify_update_account_queue, g_object_ref (info->mail_op));
1845 /* Free thread resources. Will be called after all previous idles */
1846 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1852 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1853 TnyList *header_list,
1854 GetMsgAsyncUserCallback user_callback,
1856 GDestroyNotify notify)
1858 TnyHeader *header = NULL;
1859 TnyFolder *folder = NULL;
1861 ModestMailOperationPrivate *priv = NULL;
1862 GetFullMsgsInfo *info = NULL;
1863 gboolean size_ok = TRUE;
1865 TnyIterator *iter = NULL;
1867 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1869 /* Init mail operation */
1870 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1871 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1873 priv->total = tny_list_get_length(header_list);
1875 /* Get account and set it into mail_operation */
1876 if (tny_list_get_length (header_list) >= 1) {
1877 iter = tny_list_create_iterator (header_list);
1878 header = TNY_HEADER (tny_iterator_get_current (iter));
1879 folder = tny_header_get_folder (header);
1880 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1881 g_object_unref (header);
1882 g_object_unref (folder);
1884 if (tny_list_get_length (header_list) == 1) {
1885 g_object_unref (iter);
1890 /* Get msg size limit */
1891 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1892 MODEST_CONF_MSG_SIZE_LIMIT,
1895 g_clear_error (&(priv->error));
1896 max_size = G_MAXINT;
1898 max_size = max_size * KB;
1901 /* Check message size limits. If there is only one message
1902 always retrieve it */
1904 while (!tny_iterator_is_done (iter) && size_ok) {
1905 header = TNY_HEADER (tny_iterator_get_current (iter));
1906 if (tny_header_get_message_size (header) >= max_size)
1908 g_object_unref (header);
1909 tny_iterator_next (iter);
1911 g_object_unref (iter);
1915 /* Create the info */
1916 info = g_slice_new0 (GetFullMsgsInfo);
1917 info->mail_op = self;
1918 info->user_callback = user_callback;
1919 info->user_data = user_data;
1920 info->headers = g_object_ref (header_list);
1921 info->notify = notify;
1923 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1925 /* Set status failed and set an error */
1926 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1927 /* FIXME: the error msg is different for pop */
1928 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1929 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1930 _("emev_ni_ui_imap_msg_size_exceed_error"));
1931 /* Remove from queue and free resources */
1932 modest_mail_operation_notify_end (self);
1940 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
1941 gboolean remove_to_trash /*ignored*/)
1944 ModestMailOperationPrivate *priv;
1946 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1947 g_return_if_fail (TNY_IS_HEADER (header));
1949 if (remove_to_trash)
1950 g_warning ("remove to trash is not implemented");
1952 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1953 folder = tny_header_get_folder (header);
1955 /* Get account and set it into mail_operation */
1956 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1958 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1961 tny_folder_remove_msg (folder, header, &(priv->error));
1963 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
1965 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
1966 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
1967 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
1968 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
1971 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
1977 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1979 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1982 g_object_unref (G_OBJECT (folder));
1984 /* Notify about operation end */
1985 modest_mail_operation_notify_end (self);
1989 transfer_msgs_status_cb (GObject *obj,
1993 XFerMsgAsyncHelper *helper = NULL;
1994 ModestMailOperation *self;
1995 ModestMailOperationPrivate *priv;
1996 ModestMailOperationState *state;
1999 g_return_if_fail (status != NULL);
2000 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2002 helper = (XFerMsgAsyncHelper *) user_data;
2003 g_return_if_fail (helper != NULL);
2005 self = helper->mail_op;
2006 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2008 priv->done = status->position;
2009 priv->total = status->of_total;
2011 state = modest_mail_operation_clone_state (self);
2012 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2013 g_slice_free (ModestMailOperationState, state);
2018 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2020 XFerMsgAsyncHelper *helper;
2021 ModestMailOperation *self;
2022 ModestMailOperationPrivate *priv;
2024 helper = (XFerMsgAsyncHelper *) user_data;
2025 self = helper->mail_op;
2027 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2030 priv->error = g_error_copy (*err);
2032 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2033 } else if (cancelled) {
2034 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2035 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2036 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2037 _("Error trying to refresh the contents of %s"),
2038 tny_folder_get_name (folder));
2041 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2044 /* Notify about operation end */
2045 modest_mail_operation_notify_end (self);
2047 /* If user defined callback function was defined, call it */
2048 if (helper->user_callback) {
2049 gdk_threads_enter ();
2050 helper->user_callback (priv->source, helper->user_data);
2051 gdk_threads_leave ();
2055 g_object_unref (helper->headers);
2056 g_object_unref (helper->dest_folder);
2057 g_object_unref (helper->mail_op);
2058 g_slice_free (XFerMsgAsyncHelper, helper);
2059 g_object_unref (folder);
2064 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2067 gboolean delete_original,
2068 XferMsgsAsynUserCallback user_callback,
2071 ModestMailOperationPrivate *priv;
2073 TnyFolder *src_folder;
2074 XFerMsgAsyncHelper *helper;
2076 ModestTnyFolderRules rules;
2077 const gchar *id1 = NULL;
2078 const gchar *id2 = NULL;
2079 gboolean same_folder = FALSE;
2081 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2082 g_return_if_fail (TNY_IS_LIST (headers));
2083 g_return_if_fail (TNY_IS_FOLDER (folder));
2085 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2088 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2090 /* Apply folder rules */
2091 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2092 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2093 /* Set status failed and set an error */
2094 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2095 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2096 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2097 _("ckct_ib_unable_to_paste_here"));
2098 /* Notify the queue */
2099 modest_mail_operation_notify_end (self);
2103 /* Get source folder */
2104 iter = tny_list_create_iterator (headers);
2105 header = TNY_HEADER (tny_iterator_get_current (iter));
2106 src_folder = tny_header_get_folder (header);
2107 g_object_unref (header);
2108 g_object_unref (iter);
2110 /* Check folder source and destination */
2111 id1 = tny_folder_get_id (src_folder);
2112 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2113 same_folder = !g_ascii_strcasecmp (id1, id2);
2115 /* Set status failed and set an error */
2116 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2117 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2118 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2119 _("mcen_ib_unable_to_copy_samefolder"));
2121 /* Notify the queue */
2122 modest_mail_operation_notify_end (self);
2125 g_object_unref (src_folder);
2129 /* Create the helper */
2130 helper = g_slice_new0 (XFerMsgAsyncHelper);
2131 helper->mail_op = g_object_ref(self);
2132 helper->dest_folder = g_object_ref(folder);
2133 helper->headers = g_object_ref(headers);
2134 helper->user_callback = user_callback;
2135 helper->user_data = user_data;
2137 /* Get account and set it into mail_operation */
2138 priv->account = modest_tny_folder_get_account (src_folder);
2140 /* Transfer messages */
2141 tny_folder_transfer_msgs_async (src_folder,
2146 transfer_msgs_status_cb,
2152 on_refresh_folder (TnyFolder *folder,
2157 RefreshAsyncHelper *helper = NULL;
2158 ModestMailOperation *self = NULL;
2159 ModestMailOperationPrivate *priv = NULL;
2161 helper = (RefreshAsyncHelper *) user_data;
2162 self = helper->mail_op;
2163 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2166 priv->error = g_error_copy (*error);
2167 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2172 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2173 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2174 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2175 _("Error trying to refresh the contents of %s"),
2176 tny_folder_get_name (folder));
2180 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2183 /* Call user defined callback, if it exists */
2184 if (helper->user_callback) {
2185 gdk_threads_enter ();
2186 helper->user_callback (self, folder, helper->user_data);
2187 gdk_threads_leave ();
2191 g_object_unref (helper->mail_op);
2192 g_slice_free (RefreshAsyncHelper, helper);
2193 g_object_unref (folder);
2195 /* Notify about operation end */
2196 modest_mail_operation_notify_end (self);
2200 on_refresh_folder_status_update (GObject *obj,
2204 RefreshAsyncHelper *helper = NULL;
2205 ModestMailOperation *self = NULL;
2206 ModestMailOperationPrivate *priv = NULL;
2207 ModestMailOperationState *state;
2209 g_return_if_fail (user_data != NULL);
2210 g_return_if_fail (status != NULL);
2211 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2213 helper = (RefreshAsyncHelper *) user_data;
2214 self = helper->mail_op;
2215 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2217 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2219 priv->done = status->position;
2220 priv->total = status->of_total;
2222 state = modest_mail_operation_clone_state (self);
2223 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2224 g_slice_free (ModestMailOperationState, state);
2228 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2230 RefreshAsyncUserCallback user_callback,
2233 ModestMailOperationPrivate *priv = NULL;
2234 RefreshAsyncHelper *helper = NULL;
2236 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2238 /* Pick a reference */
2239 g_object_ref (folder);
2241 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2243 /* Get account and set it into mail_operation */
2244 priv->account = modest_tny_folder_get_account (folder);
2246 /* Create the helper */
2247 helper = g_slice_new0 (RefreshAsyncHelper);
2248 helper->mail_op = g_object_ref(self);
2249 helper->user_callback = user_callback;
2250 helper->user_data = user_data;
2252 /* Refresh the folder. TODO: tinymail could issue a status
2253 updates before the callback call then this could happen. We
2254 must review the design */
2255 tny_folder_refresh_async (folder,
2257 on_refresh_folder_status_update,
2263 * It's used by the mail operation queue to notify the observers
2264 * attached to that signal that the operation finished. We need to use
2265 * that because tinymail does not give us the progress of a given
2266 * operation when it finishes (it directly calls the operation
2270 modest_mail_operation_notify_end (ModestMailOperation *self)
2272 ModestMailOperationState *state;
2273 ModestMailOperationPrivate *priv = NULL;
2275 g_return_if_fail (self);
2277 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2280 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
2284 /* Set the account back to not busy */
2285 if (priv->account_name) {
2286 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2287 priv->account_name, FALSE);
2288 g_free(priv->account_name);
2289 priv->account_name = NULL;
2292 /* Notify the observers about the mail opertation end */
2293 state = modest_mail_operation_clone_state (self);
2294 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2295 g_slice_free (ModestMailOperationState, state);