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);
1097 /* Perform send (if operation was not cancelled) */
1098 if (did_a_cancel) goto out;
1099 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1102 if (priv->account != NULL)
1103 g_object_unref (priv->account);
1104 priv->account = g_object_ref (info->transport_account);
1106 send_queue = modest_runtime_get_send_queue (info->transport_account);
1108 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
1109 modest_tny_send_queue_try_to_send (send_queue);
1110 g_source_remove (timeout);
1112 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1113 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1114 "cannot create a send queue for %s\n",
1115 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1116 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1119 /* Check if the operation was a success */
1121 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1123 /* Update the last updated key */
1124 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1125 set_last_updated_idle,
1126 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1127 (GDestroyNotify) g_free);
1132 if (info->callback) {
1133 UpdateAccountInfo *idle_info;
1135 /* This thread is not in the main lock */
1136 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1137 idle_info->mail_op = g_object_ref (info->mail_op);
1138 idle_info->new_headers = (new_headers) ? new_headers->len : 0;
1139 idle_info->callback = info->callback;
1140 g_idle_add (idle_update_account_cb, idle_info);
1143 /* Notify about operation end. Note that the info could be
1144 freed before this idle happens, but the mail operation will
1146 g_idle_add (idle_notify_update_account_queue, g_object_ref (info->mail_op));
1149 g_object_unref (query);
1150 g_object_unref (all_folders);
1151 g_object_unref (info->account);
1152 g_object_unref (info->transport_account);
1153 g_free (info->retrieve_type);
1154 g_slice_free (UpdateAccountInfo, info);
1162 modest_mail_operation_update_account (ModestMailOperation *self,
1163 const gchar *account_name,
1164 UpdateAccountCallback callback,
1168 UpdateAccountInfo *info;
1169 ModestMailOperationPrivate *priv;
1170 ModestAccountMgr *mgr;
1171 TnyStoreAccount *modest_account;
1172 TnyTransportAccount *transport_account;
1174 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1175 g_return_val_if_fail (account_name, FALSE);
1177 /* Init mail operation. Set total and done to 0, and do not
1178 update them, this way the progress objects will know that
1179 we have no clue about the number of the objects */
1180 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1183 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1185 /* Make sure that we have a connection, and request one
1187 * TODO: Is there some way to trigger this for every attempt to
1188 * use the network? */
1189 if (!modest_platform_connect_and_wait (NULL))
1192 /* Get the Modest account */
1193 modest_account = (TnyStoreAccount *)
1194 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1196 TNY_ACCOUNT_TYPE_STORE);
1198 if (!modest_account) {
1199 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1200 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1201 "cannot get tny store account for %s\n", account_name);
1206 /* Get the transport account, we can not do it in the thread
1207 due to some problems with dbus */
1208 transport_account = (TnyTransportAccount *)
1209 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1211 if (!transport_account) {
1212 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1213 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1214 "cannot get tny transport account for %s\n", account_name);
1218 /* Create the helper object */
1219 info = g_slice_new (UpdateAccountInfo);
1220 info->mail_op = self;
1221 info->account = modest_account;
1222 info->transport_account = transport_account;
1223 info->callback = callback;
1224 info->user_data = user_data;
1226 /* Get the message size limit */
1227 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1228 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1229 if (info->max_size == 0)
1230 info->max_size = G_MAXINT;
1232 info->max_size = info->max_size * KB;
1234 /* Get per-account retrieval type */
1235 mgr = modest_runtime_get_account_mgr ();
1236 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1237 MODEST_ACCOUNT_RETRIEVE, FALSE);
1239 /* Get per-account message amount retrieval limit */
1240 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1241 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1242 if (info->retrieve_limit == 0)
1243 info->retrieve_limit = G_MAXINT;
1245 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1247 /* Set account busy */
1248 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1249 priv->account_name = g_strdup(account_name);
1251 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1256 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1258 callback (self, 0, user_data);
1259 modest_mail_operation_notify_end (self);
1263 /* ******************************************************************* */
1264 /* ************************** STORE ACTIONS ************************* */
1265 /* ******************************************************************* */
1269 modest_mail_operation_create_folder (ModestMailOperation *self,
1270 TnyFolderStore *parent,
1273 ModestMailOperationPrivate *priv;
1274 TnyFolder *new_folder = NULL;
1276 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1277 g_return_val_if_fail (name, NULL);
1279 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1282 if (TNY_IS_FOLDER (parent)) {
1283 /* Check folder rules */
1284 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1285 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1286 /* Set status failed and set an error */
1287 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1288 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1289 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1290 _("mail_in_ui_folder_create_error"));
1294 if (!strcmp (name, " ") || strchr (name, '/')) {
1295 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1296 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1297 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1298 _("mail_in_ui_folder_create_error"));
1302 /* Create the folder */
1303 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1304 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1306 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1309 /* Notify about operation end */
1310 modest_mail_operation_notify_end (self);
1316 modest_mail_operation_remove_folder (ModestMailOperation *self,
1318 gboolean remove_to_trash)
1320 TnyAccount *account;
1321 ModestMailOperationPrivate *priv;
1322 ModestTnyFolderRules rules;
1324 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1325 g_return_if_fail (TNY_IS_FOLDER (folder));
1327 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1329 /* Check folder rules */
1330 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1331 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1332 /* Set status failed and set an error */
1333 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1334 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1335 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1336 _("mail_in_ui_folder_delete_error"));
1340 /* Get the account */
1341 account = modest_tny_folder_get_account (folder);
1342 priv->account = g_object_ref(account);
1344 /* Delete folder or move to trash */
1345 if (remove_to_trash) {
1346 TnyFolder *trash_folder = NULL;
1347 trash_folder = modest_tny_account_get_special_folder (account,
1348 TNY_FOLDER_TYPE_TRASH);
1349 /* TODO: error_handling */
1350 modest_mail_operation_xfer_folder (self, folder,
1351 TNY_FOLDER_STORE (trash_folder),
1354 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1356 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1357 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1360 g_object_unref (G_OBJECT (parent));
1362 g_object_unref (G_OBJECT (account));
1365 /* Notify about operation end */
1366 modest_mail_operation_notify_end (self);
1370 transfer_folder_status_cb (GObject *obj,
1374 ModestMailOperation *self;
1375 ModestMailOperationPrivate *priv;
1376 ModestMailOperationState *state;
1377 XFerMsgAsyncHelper *helper;
1379 g_return_if_fail (status != NULL);
1380 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1382 helper = (XFerMsgAsyncHelper *) user_data;
1383 g_return_if_fail (helper != NULL);
1385 self = helper->mail_op;
1386 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1388 priv->done = status->position;
1389 priv->total = status->of_total;
1391 state = modest_mail_operation_clone_state (self);
1392 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1393 g_slice_free (ModestMailOperationState, state);
1398 transfer_folder_cb (TnyFolder *folder,
1399 TnyFolderStore *into,
1401 TnyFolder *new_folder,
1405 XFerMsgAsyncHelper *helper;
1406 ModestMailOperation *self = NULL;
1407 ModestMailOperationPrivate *priv = NULL;
1409 helper = (XFerMsgAsyncHelper *) user_data;
1410 g_return_if_fail (helper != NULL);
1412 self = helper->mail_op;
1413 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1416 priv->error = g_error_copy (*err);
1418 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1419 } else if (cancelled) {
1420 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1421 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1422 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1423 _("Transference of %s was cancelled."),
1424 tny_folder_get_name (folder));
1427 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1430 /* Notify about operation end */
1431 modest_mail_operation_notify_end (self);
1433 /* If user defined callback function was defined, call it */
1434 if (helper->user_callback) {
1435 gdk_threads_enter ();
1436 helper->user_callback (priv->source, helper->user_data);
1437 gdk_threads_leave ();
1441 g_object_unref (helper->mail_op);
1442 g_slice_free (XFerMsgAsyncHelper, helper);
1443 g_object_unref (folder);
1444 g_object_unref (into);
1448 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1450 TnyFolderStore *parent,
1451 gboolean delete_original,
1452 XferMsgsAsynUserCallback user_callback,
1455 ModestMailOperationPrivate *priv = NULL;
1456 ModestTnyFolderRules parent_rules = 0, rules;
1457 XFerMsgAsyncHelper *helper = NULL;
1459 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1460 g_return_if_fail (TNY_IS_FOLDER (folder));
1462 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1464 /* Get account and set it into mail_operation */
1465 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1466 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1468 /* Get folder rules */
1469 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1470 if (TNY_IS_FOLDER (parent))
1471 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1473 /* The moveable restriction is applied also to copy operation */
1474 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1475 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1476 /* Set status failed and set an error */
1477 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1478 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1479 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1480 _("mail_in_ui_folder_move_target_error"));
1482 /* Notify the queue */
1483 modest_mail_operation_notify_end (self);
1484 } else if (TNY_IS_FOLDER (parent) &&
1485 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1486 /* Set status failed and set an error */
1487 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1488 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1489 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1490 _("FIXME: parent folder does not accept new folders"));
1492 /* Notify the queue */
1493 modest_mail_operation_notify_end (self);
1495 /* Pick references for async calls */
1496 g_object_ref (folder);
1497 g_object_ref (parent);
1499 /* Create the helper */
1500 helper = g_slice_new0 (XFerMsgAsyncHelper);
1501 helper->mail_op = g_object_ref(self);
1502 helper->dest_folder = NULL;
1503 helper->headers = NULL;
1504 helper->user_callback = user_callback;
1505 helper->user_data = user_data;
1507 /* Move/Copy folder */
1508 tny_folder_copy_async (folder,
1510 tny_folder_get_name (folder),
1513 transfer_folder_status_cb,
1520 modest_mail_operation_rename_folder (ModestMailOperation *self,
1524 ModestMailOperationPrivate *priv;
1525 ModestTnyFolderRules rules;
1526 XFerMsgAsyncHelper *helper;
1528 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1529 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1530 g_return_if_fail (name);
1532 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1534 /* Get account and set it into mail_operation */
1535 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1537 /* Check folder rules */
1538 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1539 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1540 /* Set status failed and set an error */
1541 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1542 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1543 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1544 _("FIXME: unable to rename"));
1546 /* Notify about operation end */
1547 modest_mail_operation_notify_end (self);
1548 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1549 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1550 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1551 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1552 _("FIXME: unable to rename"));
1553 /* Notify about operation end */
1554 modest_mail_operation_notify_end (self);
1556 TnyFolderStore *into;
1558 /* Create the helper */
1559 helper = g_slice_new0 (XFerMsgAsyncHelper);
1560 helper->mail_op = g_object_ref(self);
1561 helper->dest_folder = NULL;
1562 helper->headers = NULL;
1563 helper->user_callback = NULL;
1564 helper->user_data = NULL;
1566 /* Rename. Camel handles folder subscription/unsubscription */
1567 into = tny_folder_get_folder_store (folder);
1568 tny_folder_copy_async (folder, into, name, TRUE,
1570 transfer_folder_status_cb,
1574 g_object_unref (into);
1578 /* ******************************************************************* */
1579 /* ************************** MSG ACTIONS ************************* */
1580 /* ******************************************************************* */
1582 void modest_mail_operation_get_msg (ModestMailOperation *self,
1584 GetMsgAsyncUserCallback user_callback,
1587 GetMsgAsyncHelper *helper = NULL;
1589 ModestMailOperationPrivate *priv;
1591 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1592 g_return_if_fail (TNY_IS_HEADER (header));
1594 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1595 folder = tny_header_get_folder (header);
1597 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1599 /* Get message from folder */
1601 /* Get account and set it into mail_operation */
1602 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1604 helper = g_slice_new0 (GetMsgAsyncHelper);
1605 helper->mail_op = self;
1606 helper->user_callback = user_callback;
1607 helper->user_data = user_data;
1608 helper->header = g_object_ref (header);
1610 // The callback's reference so that the mail op is not
1611 // finalized until the async operation is completed even if
1612 // the user canceled the request meanwhile.
1613 g_object_ref (G_OBJECT (helper->mail_op));
1615 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1617 g_object_unref (G_OBJECT (folder));
1619 /* Set status failed and set an error */
1620 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1621 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1622 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1623 _("Error trying to get a message. No folder found for header"));
1625 /* Notify the queue */
1626 modest_mail_operation_notify_end (self);
1631 get_msg_cb (TnyFolder *folder,
1637 GetMsgAsyncHelper *helper = NULL;
1638 ModestMailOperation *self = NULL;
1639 ModestMailOperationPrivate *priv = NULL;
1641 helper = (GetMsgAsyncHelper *) user_data;
1642 g_return_if_fail (helper != NULL);
1643 self = helper->mail_op;
1644 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1645 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1647 /* Check errors and cancel */
1649 priv->error = g_error_copy (*error);
1650 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1651 } else if (cancelled) {
1652 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1653 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1654 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1655 _("Error trying to refresh the contents of %s"),
1656 tny_folder_get_name (folder));
1658 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1661 /* If user defined callback function was defined, call it even
1662 if the operation failed*/
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 ();
1672 g_object_unref (helper->mail_op);
1673 g_object_unref (helper->header);
1674 g_slice_free (GetMsgAsyncHelper, helper);
1676 /* Notify about operation end */
1677 modest_mail_operation_notify_end (self);
1681 get_msg_status_cb (GObject *obj,
1685 GetMsgAsyncHelper *helper = NULL;
1686 ModestMailOperation *self;
1687 ModestMailOperationPrivate *priv;
1688 ModestMailOperationState *state;
1690 g_return_if_fail (status != NULL);
1691 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1693 helper = (GetMsgAsyncHelper *) user_data;
1694 g_return_if_fail (helper != NULL);
1696 self = helper->mail_op;
1697 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1699 if(priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1705 state = modest_mail_operation_clone_state (self);
1706 state->bytes_done = status->position;
1707 state->bytes_total = status->of_total;
1708 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1709 g_slice_free (ModestMailOperationState, state);
1712 /****************************************************/
1714 ModestMailOperation *mail_op;
1716 GetMsgAsyncUserCallback user_callback;
1718 GDestroyNotify notify;
1722 GetMsgAsyncUserCallback user_callback;
1726 ModestMailOperation *mail_op;
1727 } NotifyGetMsgsInfo;
1731 * Used by get_msgs_full_thread to call the user_callback for each
1732 * message that has been read
1735 notify_get_msgs_full (gpointer data)
1737 NotifyGetMsgsInfo *info;
1739 info = (NotifyGetMsgsInfo *) data;
1741 /* Call the user callback. Idles are not in the main lock, so
1743 gdk_threads_enter ();
1744 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1745 gdk_threads_leave ();
1747 g_slice_free (NotifyGetMsgsInfo, info);
1753 * Used by get_msgs_full_thread to free al the thread resources and to
1754 * call the destroy function for the passed user_data
1757 get_msgs_full_destroyer (gpointer data)
1759 GetFullMsgsInfo *info;
1761 info = (GetFullMsgsInfo *) data;
1764 gdk_threads_enter ();
1765 info->notify (info->user_data);
1766 gdk_threads_leave ();
1770 g_object_unref (info->headers);
1771 g_slice_free (GetFullMsgsInfo, info);
1777 get_msgs_full_thread (gpointer thr_user_data)
1779 GetFullMsgsInfo *info;
1780 ModestMailOperationPrivate *priv = NULL;
1781 TnyIterator *iter = NULL;
1783 info = (GetFullMsgsInfo *) thr_user_data;
1784 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1786 iter = tny_list_create_iterator (info->headers);
1787 while (!tny_iterator_is_done (iter)) {
1791 header = TNY_HEADER (tny_iterator_get_current (iter));
1792 folder = tny_header_get_folder (header);
1794 /* Get message from folder */
1797 /* The callback will call it per each header */
1798 msg = tny_folder_get_msg (folder, header, &(priv->error));
1801 ModestMailOperationState *state;
1806 /* notify progress */
1807 state = modest_mail_operation_clone_state (info->mail_op);
1808 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1809 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1810 pair, (GDestroyNotify) modest_pair_free);
1812 /* The callback is the responsible for
1813 freeing the message */
1814 if (info->user_callback) {
1815 NotifyGetMsgsInfo *info_notify;
1816 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1817 info_notify->user_callback = info->user_callback;
1818 info_notify->mail_op = info->mail_op;
1819 info_notify->header = g_object_ref (header);
1820 info_notify->msg = g_object_ref (msg);
1821 info_notify->user_data = info->user_data;
1822 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1823 notify_get_msgs_full,
1826 g_object_unref (msg);
1829 /* Set status failed and set an error */
1830 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1831 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1832 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1833 "Error trying to get a message. No folder found for header");
1835 g_object_unref (header);
1836 tny_iterator_next (iter);
1839 /* Set operation status */
1840 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1841 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1843 /* Notify about operation end */
1844 g_idle_add (idle_notify_update_account_queue, g_object_ref (info->mail_op));
1846 /* Free thread resources. Will be called after all previous idles */
1847 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1853 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1854 TnyList *header_list,
1855 GetMsgAsyncUserCallback user_callback,
1857 GDestroyNotify notify)
1859 TnyHeader *header = NULL;
1860 TnyFolder *folder = NULL;
1862 ModestMailOperationPrivate *priv = NULL;
1863 GetFullMsgsInfo *info = NULL;
1864 gboolean size_ok = TRUE;
1866 TnyIterator *iter = NULL;
1868 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1870 /* Init mail operation */
1871 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1872 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1874 priv->total = tny_list_get_length(header_list);
1876 /* Get account and set it into mail_operation */
1877 if (tny_list_get_length (header_list) >= 1) {
1878 iter = tny_list_create_iterator (header_list);
1879 header = TNY_HEADER (tny_iterator_get_current (iter));
1880 folder = tny_header_get_folder (header);
1881 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1882 g_object_unref (header);
1883 g_object_unref (folder);
1885 if (tny_list_get_length (header_list) == 1) {
1886 g_object_unref (iter);
1891 /* Get msg size limit */
1892 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1893 MODEST_CONF_MSG_SIZE_LIMIT,
1896 g_clear_error (&(priv->error));
1897 max_size = G_MAXINT;
1899 max_size = max_size * KB;
1902 /* Check message size limits. If there is only one message
1903 always retrieve it */
1905 while (!tny_iterator_is_done (iter) && size_ok) {
1906 header = TNY_HEADER (tny_iterator_get_current (iter));
1907 if (tny_header_get_message_size (header) >= max_size)
1909 g_object_unref (header);
1910 tny_iterator_next (iter);
1912 g_object_unref (iter);
1916 /* Create the info */
1917 info = g_slice_new0 (GetFullMsgsInfo);
1918 info->mail_op = self;
1919 info->user_callback = user_callback;
1920 info->user_data = user_data;
1921 info->headers = g_object_ref (header_list);
1922 info->notify = notify;
1924 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1926 /* Set status failed and set an error */
1927 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1928 /* FIXME: the error msg is different for pop */
1929 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1930 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1931 _("emev_ni_ui_imap_msg_size_exceed_error"));
1932 /* Remove from queue and free resources */
1933 modest_mail_operation_notify_end (self);
1941 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
1942 gboolean remove_to_trash /*ignored*/)
1945 ModestMailOperationPrivate *priv;
1947 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1948 g_return_if_fail (TNY_IS_HEADER (header));
1950 if (remove_to_trash)
1951 g_warning ("remove to trash is not implemented");
1953 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1954 folder = tny_header_get_folder (header);
1956 /* Get account and set it into mail_operation */
1957 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1959 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1962 tny_folder_remove_msg (folder, header, &(priv->error));
1964 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
1966 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
1967 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
1968 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
1969 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
1972 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
1978 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1980 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1983 g_object_unref (G_OBJECT (folder));
1985 /* Notify about operation end */
1986 modest_mail_operation_notify_end (self);
1990 transfer_msgs_status_cb (GObject *obj,
1994 XFerMsgAsyncHelper *helper = NULL;
1995 ModestMailOperation *self;
1996 ModestMailOperationPrivate *priv;
1997 ModestMailOperationState *state;
2000 g_return_if_fail (status != NULL);
2001 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2003 helper = (XFerMsgAsyncHelper *) user_data;
2004 g_return_if_fail (helper != NULL);
2006 self = helper->mail_op;
2007 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2009 priv->done = status->position;
2010 priv->total = status->of_total;
2012 state = modest_mail_operation_clone_state (self);
2013 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2014 g_slice_free (ModestMailOperationState, state);
2019 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2021 XFerMsgAsyncHelper *helper;
2022 ModestMailOperation *self;
2023 ModestMailOperationPrivate *priv;
2025 helper = (XFerMsgAsyncHelper *) user_data;
2026 self = helper->mail_op;
2028 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2031 priv->error = g_error_copy (*err);
2033 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2034 } else if (cancelled) {
2035 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2036 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2037 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2038 _("Error trying to refresh the contents of %s"),
2039 tny_folder_get_name (folder));
2042 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2045 /* Notify about operation end */
2046 modest_mail_operation_notify_end (self);
2048 /* If user defined callback function was defined, call it */
2049 if (helper->user_callback) {
2050 gdk_threads_enter ();
2051 helper->user_callback (priv->source, helper->user_data);
2052 gdk_threads_leave ();
2056 g_object_unref (helper->headers);
2057 g_object_unref (helper->dest_folder);
2058 g_object_unref (helper->mail_op);
2059 g_slice_free (XFerMsgAsyncHelper, helper);
2060 g_object_unref (folder);
2065 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2068 gboolean delete_original,
2069 XferMsgsAsynUserCallback user_callback,
2072 ModestMailOperationPrivate *priv;
2074 TnyFolder *src_folder;
2075 XFerMsgAsyncHelper *helper;
2077 ModestTnyFolderRules rules;
2078 const gchar *id1 = NULL;
2079 const gchar *id2 = NULL;
2080 gboolean same_folder = FALSE;
2082 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2083 g_return_if_fail (TNY_IS_LIST (headers));
2084 g_return_if_fail (TNY_IS_FOLDER (folder));
2086 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2089 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2091 /* Apply folder rules */
2092 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2093 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2094 /* Set status failed and set an error */
2095 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2096 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2097 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2098 _("ckct_ib_unable_to_paste_here"));
2099 /* Notify the queue */
2100 modest_mail_operation_notify_end (self);
2104 /* Get source folder */
2105 iter = tny_list_create_iterator (headers);
2106 header = TNY_HEADER (tny_iterator_get_current (iter));
2107 src_folder = tny_header_get_folder (header);
2108 g_object_unref (header);
2109 g_object_unref (iter);
2111 /* Check folder source and destination */
2112 id1 = tny_folder_get_id (src_folder);
2113 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2114 same_folder = !g_ascii_strcasecmp (id1, id2);
2116 /* Set status failed and set an error */
2117 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2118 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2119 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2120 _("mcen_ib_unable_to_copy_samefolder"));
2122 /* Notify the queue */
2123 modest_mail_operation_notify_end (self);
2126 g_object_unref (src_folder);
2130 /* Create the helper */
2131 helper = g_slice_new0 (XFerMsgAsyncHelper);
2132 helper->mail_op = g_object_ref(self);
2133 helper->dest_folder = g_object_ref(folder);
2134 helper->headers = g_object_ref(headers);
2135 helper->user_callback = user_callback;
2136 helper->user_data = user_data;
2138 /* Get account and set it into mail_operation */
2139 priv->account = modest_tny_folder_get_account (src_folder);
2141 /* Transfer messages */
2142 tny_folder_transfer_msgs_async (src_folder,
2147 transfer_msgs_status_cb,
2153 on_refresh_folder (TnyFolder *folder,
2158 RefreshAsyncHelper *helper = NULL;
2159 ModestMailOperation *self = NULL;
2160 ModestMailOperationPrivate *priv = NULL;
2162 helper = (RefreshAsyncHelper *) user_data;
2163 self = helper->mail_op;
2164 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2167 priv->error = g_error_copy (*error);
2168 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2173 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2174 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2175 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2176 _("Error trying to refresh the contents of %s"),
2177 tny_folder_get_name (folder));
2181 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2184 /* Call user defined callback, if it exists */
2185 if (helper->user_callback) {
2186 gdk_threads_enter ();
2187 helper->user_callback (self, folder, helper->user_data);
2188 gdk_threads_leave ();
2192 g_object_unref (helper->mail_op);
2193 g_slice_free (RefreshAsyncHelper, helper);
2194 g_object_unref (folder);
2196 /* Notify about operation end */
2197 modest_mail_operation_notify_end (self);
2201 on_refresh_folder_status_update (GObject *obj,
2205 RefreshAsyncHelper *helper = NULL;
2206 ModestMailOperation *self = NULL;
2207 ModestMailOperationPrivate *priv = NULL;
2208 ModestMailOperationState *state;
2210 g_return_if_fail (user_data != NULL);
2211 g_return_if_fail (status != NULL);
2212 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2214 helper = (RefreshAsyncHelper *) user_data;
2215 self = helper->mail_op;
2216 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2218 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2220 priv->done = status->position;
2221 priv->total = status->of_total;
2223 state = modest_mail_operation_clone_state (self);
2224 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2225 g_slice_free (ModestMailOperationState, state);
2229 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2231 RefreshAsyncUserCallback user_callback,
2234 ModestMailOperationPrivate *priv = NULL;
2235 RefreshAsyncHelper *helper = NULL;
2237 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2239 /* Pick a reference */
2240 g_object_ref (folder);
2242 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2244 /* Get account and set it into mail_operation */
2245 priv->account = modest_tny_folder_get_account (folder);
2247 /* Create the helper */
2248 helper = g_slice_new0 (RefreshAsyncHelper);
2249 helper->mail_op = g_object_ref(self);
2250 helper->user_callback = user_callback;
2251 helper->user_data = user_data;
2253 /* Refresh the folder. TODO: tinymail could issue a status
2254 updates before the callback call then this could happen. We
2255 must review the design */
2256 tny_folder_refresh_async (folder,
2258 on_refresh_folder_status_update,
2264 * It's used by the mail operation queue to notify the observers
2265 * attached to that signal that the operation finished. We need to use
2266 * that because tinymail does not give us the progress of a given
2267 * operation when it finishes (it directly calls the operation
2271 modest_mail_operation_notify_end (ModestMailOperation *self)
2273 ModestMailOperationState *state;
2274 ModestMailOperationPrivate *priv = NULL;
2276 g_return_if_fail (self);
2278 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2281 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
2285 /* Set the account back to not busy */
2286 if (priv->account_name) {
2287 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2288 priv->account_name, FALSE);
2289 g_free(priv->account_name);
2290 priv->account_name = NULL;
2293 /* Notify the observers about the mail opertation end */
2294 state = modest_mail_operation_clone_state (self);
2295 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2296 g_slice_free (ModestMailOperationState, state);