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.
30 #include "modest-mail-operation.h"
31 /* include other impl specific header files */
34 #include <tny-mime-part.h>
35 #include <tny-store-account.h>
36 #include <tny-folder-store.h>
37 #include <tny-folder-store-query.h>
38 #include <tny-camel-stream.h>
39 #include <tny-simple-list.h>
40 #include <tny-send-queue.h>
41 #include <tny-status.h>
42 #include <camel/camel-stream-mem.h>
43 #include <glib/gi18n.h>
44 #include "modest-platform.h"
45 #include <modest-tny-account.h>
46 #include <modest-tny-send-queue.h>
47 #include <modest-runtime.h>
48 #include "modest-text-utils.h"
49 #include "modest-tny-msg.h"
50 #include "modest-tny-folder.h"
51 #include "modest-tny-platform-factory.h"
52 #include "modest-marshal.h"
53 #include "modest-error.h"
55 /* 'private'/'protected' functions */
56 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
57 static void modest_mail_operation_init (ModestMailOperation *obj);
58 static void modest_mail_operation_finalize (GObject *obj);
60 /* static void update_process_msg_status_cb (GObject *obj, */
61 /* TnyStatus *status, */
62 /* gpointer user_data); */
63 static void get_msg_cb (TnyFolder *folder,
69 static void get_msg_status_cb (GObject *obj,
73 static void modest_mail_operation_notify_end (ModestMailOperation *self);
75 enum _ModestMailOperationSignals
77 PROGRESS_CHANGED_SIGNAL,
82 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
83 struct _ModestMailOperationPrivate {
86 ModestMailOperationStatus status;
87 ModestMailOperationId id;
89 ErrorCheckingUserCallback error_checking;
93 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
94 MODEST_TYPE_MAIL_OPERATION, \
95 ModestMailOperationPrivate))
97 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
98 priv->status = new_status;\
101 typedef struct _GetMsgAsyncHelper {
102 ModestMailOperation *mail_op;
103 GetMsgAsynUserCallback user_callback;
108 typedef struct _XFerMsgAsyncHelper
110 ModestMailOperation *mail_op;
112 TnyFolder *dest_folder;
113 XferMsgsAsynUserCallback user_callback;
115 } XFerMsgAsyncHelper;
117 typedef struct _XFerFolderAsyncHelper
119 ModestMailOperation *mail_op;
121 } XFerFolderAsyncHelper;
124 static GObjectClass *parent_class = NULL;
126 static guint signals[NUM_SIGNALS] = {0};
129 modest_mail_operation_get_type (void)
131 static GType my_type = 0;
133 static const GTypeInfo my_info = {
134 sizeof(ModestMailOperationClass),
135 NULL, /* base init */
136 NULL, /* base finalize */
137 (GClassInitFunc) modest_mail_operation_class_init,
138 NULL, /* class finalize */
139 NULL, /* class data */
140 sizeof(ModestMailOperation),
142 (GInstanceInitFunc) modest_mail_operation_init,
145 my_type = g_type_register_static (G_TYPE_OBJECT,
146 "ModestMailOperation",
153 modest_mail_operation_class_init (ModestMailOperationClass *klass)
155 GObjectClass *gobject_class;
156 gobject_class = (GObjectClass*) klass;
158 parent_class = g_type_class_peek_parent (klass);
159 gobject_class->finalize = modest_mail_operation_finalize;
161 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
164 * ModestMailOperation::progress-changed
165 * @self: the #MailOperation that emits the signal
166 * @user_data: user data set when the signal handler was connected
168 * Emitted when the progress of a mail operation changes
170 signals[PROGRESS_CHANGED_SIGNAL] =
171 g_signal_new ("progress-changed",
172 G_TYPE_FROM_CLASS (gobject_class),
174 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
176 g_cclosure_marshal_VOID__VOID,
181 modest_mail_operation_init (ModestMailOperation *obj)
183 ModestMailOperationPrivate *priv;
185 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
187 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
188 priv->id = MODEST_MAIL_OPERATION_ID_UNKNOWN;
196 modest_mail_operation_finalize (GObject *obj)
198 ModestMailOperationPrivate *priv;
200 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
203 g_error_free (priv->error);
207 g_object_unref (priv->source);
211 G_OBJECT_CLASS(parent_class)->finalize (obj);
215 modest_mail_operation_new (ModestMailOperationId id,
218 ModestMailOperation *obj;
219 ModestMailOperationPrivate *priv;
221 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
222 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
226 priv->source = g_object_ref(source);
232 modest_mail_operation_new_with_error_handling (ModestMailOperationId id,
234 ErrorCheckingUserCallback error_handler)
236 ModestMailOperation *obj;
237 ModestMailOperationPrivate *priv;
239 obj = modest_mail_operation_new (id, source);
240 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
242 g_return_val_if_fail (error_handler != NULL, obj);
243 priv->error_checking = error_handler;
249 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
251 ModestMailOperationPrivate *priv;
253 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
254 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
256 if (priv->error_checking == NULL) return;
257 priv->error_checking (priv->source, self);
261 ModestMailOperationId
262 modest_mail_operation_get_id (ModestMailOperation *self)
264 ModestMailOperationPrivate *priv;
266 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
272 modest_mail_operation_is_mine (ModestMailOperation *self,
275 ModestMailOperationPrivate *priv;
277 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
278 if (priv->source == NULL) return FALSE;
280 return priv->source == me;
285 modest_mail_operation_send_mail (ModestMailOperation *self,
286 TnyTransportAccount *transport_account,
289 TnySendQueue *send_queue;
291 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
292 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
293 g_return_if_fail (TNY_IS_MSG (msg));
295 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
296 if (!TNY_IS_SEND_QUEUE(send_queue))
297 g_printerr ("modest: could not find send queue for account\n");
300 tny_send_queue_add (send_queue, msg, &err);
302 g_printerr ("modest: error adding msg to send queue: %s\n",
306 /* g_message ("modest: message added to send queue"); */
310 /* Notify about operation end */
311 modest_mail_operation_notify_end (self);
315 modest_mail_operation_send_new_mail (ModestMailOperation *self,
316 TnyTransportAccount *transport_account,
317 const gchar *from, const gchar *to,
318 const gchar *cc, const gchar *bcc,
319 const gchar *subject, const gchar *plain_body,
320 const gchar *html_body,
321 const GList *attachments_list,
322 TnyHeaderFlags priority_flags)
325 ModestMailOperationPrivate *priv = NULL;
326 /* GList *node = NULL; */
328 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
329 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
331 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
333 /* Check parametters */
335 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
336 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
337 _("Error trying to send a mail. You need to set at least one recipient"));
341 if (html_body == NULL) {
342 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
344 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
347 g_printerr ("modest: failed to create a new msg\n");
351 /* TODO: add priority handling. It's received in the priority_flags operator, and
352 it should have effect in the sending operation */
354 /* Call mail operation */
355 modest_mail_operation_send_mail (self, transport_account, new_msg);
358 g_object_unref (G_OBJECT (new_msg));
362 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
363 TnyTransportAccount *transport_account,
364 const gchar *from, const gchar *to,
365 const gchar *cc, const gchar *bcc,
366 const gchar *subject, const gchar *plain_body,
367 const gchar *html_body,
368 const GList *attachments_list,
369 TnyHeaderFlags priority_flags)
372 TnyFolder *folder = NULL;
373 ModestMailOperationPrivate *priv = NULL;
376 /* GList *node = NULL; */
378 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
379 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
381 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
383 if (html_body == NULL) {
384 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
386 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
389 g_printerr ("modest: failed to create a new msg\n");
393 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
395 g_printerr ("modest: failed to find Drafts folder\n");
399 tny_folder_add_msg (folder, msg, &err);
401 g_printerr ("modest: error adding msg to Drafts folder: %s",
407 modest_mail_operation_notify_end (self);
412 g_object_unref (G_OBJECT(msg));
414 g_object_unref (G_OBJECT(folder));
419 ModestMailOperation *mail_op;
420 TnyStoreAccount *account;
421 TnyTransportAccount *transport_account;
425 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
428 TnyList *folders = tny_simple_list_new ();
430 tny_folder_store_get_folders (store, folders, query, NULL);
431 iter = tny_list_create_iterator (folders);
433 while (!tny_iterator_is_done (iter)) {
435 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
437 tny_list_prepend (all_folders, G_OBJECT (folder));
438 recurse_folders (folder, query, all_folders);
439 g_object_unref (G_OBJECT (folder));
441 tny_iterator_next (iter);
443 g_object_unref (G_OBJECT (iter));
444 g_object_unref (G_OBJECT (folders));
448 * Used by update_account_thread to emit the "progress-changed" signal
449 * from the main loop. We call it inside an idle call to achieve that
452 notify_update_account_observers (gpointer data)
454 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
456 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
462 * Used by update_account_thread to notify the queue from the main
463 * loop. We call it inside an idle call to achieve that
466 notify_update_account_queue (gpointer data)
468 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
470 modest_mail_operation_notify_end (mail_op);
471 g_object_unref (mail_op);
477 update_account_thread (gpointer thr_user_data)
479 UpdateAccountInfo *info;
480 TnyList *all_folders = NULL;
481 TnyIterator *iter = NULL;
482 TnyFolderStoreQuery *query = NULL;
483 ModestMailOperationPrivate *priv;
484 ModestTnySendQueue *send_queue;
487 info = (UpdateAccountInfo *) thr_user_data;
488 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
490 /* Get all the folders We can do it synchronously because
491 we're already running in a different thread than the UI */
492 all_folders = tny_simple_list_new ();
493 query = tny_folder_store_query_new ();
494 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
495 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
500 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
504 iter = tny_list_create_iterator (all_folders);
505 while (!tny_iterator_is_done (iter)) {
506 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
508 recurse_folders (folder, query, all_folders);
509 tny_iterator_next (iter);
511 g_object_unref (G_OBJECT (iter));
513 /* Update status and notify. We need to call the notification
514 with a source functopm in order to call it from the main
515 loop. We need that in order not to get into trouble with
516 Gtk+. We use a timeout in order to provide more status
517 information, because the sync tinymail call does not
518 provide it for the moment */
519 timeout = g_timeout_add (250, notify_update_account_observers, info->mail_op);
521 /* Refresh folders */
522 iter = tny_list_create_iterator (all_folders);
523 while (!tny_iterator_is_done (iter) && !priv->error) {
525 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
527 /* Refresh the folder */
528 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
530 /* TODO: Apply retrieval types */
532 /* TODO: apply per-message size limits */
534 /* TODO: apply message count limit */
537 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
540 g_object_unref (G_OBJECT (folder));
541 tny_iterator_next (iter);
543 g_object_unref (G_OBJECT (iter));
544 g_source_remove (timeout);
547 priv->id = MODEST_MAIL_OPERATION_ID_SEND;
549 send_queue = modest_tny_send_queue_new (TNY_CAMEL_TRANSPORT_ACCOUNT(info->transport_account));
551 timeout = g_timeout_add (250, notify_update_account_observers, info->mail_op);
552 modest_tny_send_queue_flush (send_queue);
553 g_source_remove (timeout);
555 g_object_unref (G_OBJECT(send_queue));
557 /* Check if the operation was a success */
559 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
561 /* Update the last updated key */
562 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
563 tny_account_get_id (TNY_ACCOUNT (info->account)),
564 MODEST_ACCOUNT_LAST_UPDATED,
570 /* Notify about operation end. Note that the info could be
571 freed before this idle happens, but the mail operation will
573 g_idle_add (notify_update_account_queue, info->mail_op);
576 g_object_unref (query);
577 g_object_unref (all_folders);
578 g_object_unref (info->account);
579 g_object_unref (info->transport_account);
580 g_slice_free (UpdateAccountInfo, info);
586 modest_mail_operation_update_account (ModestMailOperation *self,
587 const gchar *account_name)
590 UpdateAccountInfo *info;
591 ModestMailOperationPrivate *priv;
592 TnyStoreAccount *modest_account;
593 TnyTransportAccount *transport_account;
595 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
596 g_return_val_if_fail (account_name, FALSE);
598 /* Init mail operation. Set total and done to 0, and do not
599 update them, this way the progress objects will know that
600 we have no clue about the number of the objects */
601 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
604 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
606 /* Get the Modest account */
607 modest_account = (TnyStoreAccount *)
608 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
610 TNY_ACCOUNT_TYPE_STORE);
612 if (!modest_account) {
613 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
614 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
615 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
616 "cannot get tny store account for %s\n", account_name);
617 modest_mail_operation_notify_end (self);
621 /* Get the transport account, we can not do it in the thread
622 due to some problems with dbus */
623 transport_account = (TnyTransportAccount *)
624 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
626 if (!transport_account) {
627 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
628 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
629 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
630 "cannot get tny transport account for %s\n", account_name);
631 modest_mail_operation_notify_end (self);
635 /* Create the helper object */
636 info = g_slice_new (UpdateAccountInfo);
637 info->mail_op = self;
638 info->account = modest_account;
639 info->transport_account = transport_account;
641 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
646 ModestMailOperationStatus
647 modest_mail_operation_get_status (ModestMailOperation *self)
649 ModestMailOperationPrivate *priv;
651 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
652 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
653 MODEST_MAIL_OPERATION_STATUS_INVALID);
655 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
660 modest_mail_operation_get_error (ModestMailOperation *self)
662 ModestMailOperationPrivate *priv;
664 g_return_val_if_fail (self, NULL);
665 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
667 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
672 modest_mail_operation_cancel (ModestMailOperation *self)
674 ModestMailOperationPrivate *priv;
676 if (!MODEST_IS_MAIL_OPERATION (self)) {
677 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
681 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
683 /* TODO: Tinymail does not support cancel operation */
684 /* tny_account_cancel (); */
687 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
689 /* Notify about operation end */
690 modest_mail_operation_notify_end (self);
696 modest_mail_operation_get_task_done (ModestMailOperation *self)
698 ModestMailOperationPrivate *priv;
700 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
702 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
707 modest_mail_operation_get_task_total (ModestMailOperation *self)
709 ModestMailOperationPrivate *priv;
711 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
713 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
718 modest_mail_operation_is_finished (ModestMailOperation *self)
720 ModestMailOperationPrivate *priv;
721 gboolean retval = FALSE;
723 if (!MODEST_IS_MAIL_OPERATION (self)) {
724 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
728 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
730 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
731 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
732 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
733 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
742 /* ******************************************************************* */
743 /* ************************** STORE ACTIONS ************************* */
744 /* ******************************************************************* */
748 modest_mail_operation_create_folder (ModestMailOperation *self,
749 TnyFolderStore *parent,
752 ModestTnyFolderRules rules;
753 ModestMailOperationPrivate *priv;
754 TnyFolder *new_folder = NULL;
755 gboolean can_create = FALSE;
757 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
758 g_return_val_if_fail (name, NULL);
760 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
763 if (!TNY_IS_FOLDER (parent)) {
764 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
765 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
766 _("mail_in_ui_folder_create_error"));
768 /* Check folder rules */
769 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
770 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
771 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
772 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
773 _("mail_in_ui_folder_create_error"));
779 /* Create the folder */
780 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
781 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
784 /* Notify about operation end */
785 modest_mail_operation_notify_end (self);
791 modest_mail_operation_remove_folder (ModestMailOperation *self,
793 gboolean remove_to_trash)
796 ModestMailOperationPrivate *priv;
797 ModestTnyFolderRules rules;
799 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
800 g_return_if_fail (TNY_IS_FOLDER (folder));
802 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
804 /* Check folder rules */
805 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
806 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
807 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
808 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
809 _("mail_in_ui_folder_delete_error"));
813 /* Get the account */
814 account = tny_folder_get_account (folder);
816 /* Delete folder or move to trash */
817 if (remove_to_trash) {
818 TnyFolder *trash_folder = NULL;
819 trash_folder = modest_tny_account_get_special_folder (account,
820 TNY_FOLDER_TYPE_TRASH);
821 /* TODO: error_handling */
822 modest_mail_operation_xfer_folder (self, folder,
823 TNY_FOLDER_STORE (trash_folder), TRUE);
825 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
827 tny_folder_store_remove_folder (parent, folder, &(priv->error));
828 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
831 g_object_unref (G_OBJECT (parent));
833 g_object_unref (G_OBJECT (account));
836 /* Notify about operation end */
837 modest_mail_operation_notify_end (self);
841 modest_mail_operation_rename_folder (ModestMailOperation *self,
845 ModestMailOperationPrivate *priv;
846 ModestTnyFolderRules rules;
848 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
849 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
850 g_return_if_fail (name);
852 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
854 /* Check folder rules */
855 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
856 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
857 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
858 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
859 _("FIXME: unable to rename"));
861 /* Rename. Camel handles folder subscription/unsubscription */
862 TnyFolderStore *into;
865 into = tny_folder_get_folder_store (folder);
866 nfol = tny_folder_copy (folder, into, name, TRUE, &(priv->error));
868 g_object_unref (into);
870 g_object_unref (nfol);
872 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
876 /* Notify about operation end */
877 modest_mail_operation_notify_end (self);
881 transfer_folder_status_cb (GObject *obj,
885 XFerMsgAsyncHelper *helper = NULL;
886 ModestMailOperation *self;
887 ModestMailOperationPrivate *priv;
889 g_return_if_fail (status != NULL);
890 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
892 helper = (XFerMsgAsyncHelper *) user_data;
893 g_return_if_fail (helper != NULL);
895 self = helper->mail_op;
896 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
898 if ((status->position == 1) && (status->of_total == 100))
901 priv->done = status->position;
902 priv->total = status->of_total;
904 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
909 transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, gboolean cancelled, TnyFolder *new_folder, GError **err, gpointer user_data)
911 XFerFolderAsyncHelper *helper = NULL;
912 ModestMailOperation *self = NULL;
913 ModestMailOperationPrivate *priv = NULL;
915 helper = (XFerFolderAsyncHelper *) user_data;
916 self = helper->mail_op;
918 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
921 priv->error = g_error_copy (*err);
923 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
924 } else if (cancelled) {
925 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
926 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
927 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
928 _("Transference of %s was cancelled."),
929 tny_folder_get_name (folder));
932 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
936 g_slice_free (XFerFolderAsyncHelper, helper);
937 g_object_unref (folder);
938 g_object_unref (into);
939 if (new_folder != NULL)
940 g_object_unref (new_folder);
942 /* Notify about operation end */
943 modest_mail_operation_notify_end (self);
947 modest_mail_operation_xfer_folder (ModestMailOperation *self,
949 TnyFolderStore *parent,
950 gboolean delete_original)
952 XFerFolderAsyncHelper *helper = NULL;
953 ModestMailOperationPrivate *priv = NULL;
954 ModestTnyFolderRules rules;
956 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
957 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
958 g_return_if_fail (TNY_IS_FOLDER (folder));
960 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
962 /* Pick references for async calls */
963 g_object_ref (folder);
964 g_object_ref (parent);
966 /* The moveable restriction is applied also to copy operation */
967 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
968 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
969 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
970 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
971 _("FIXME: unable to rename"));
973 /* Notify the queue */
974 modest_mail_operation_notify_end (self);
976 helper = g_slice_new0 (XFerFolderAsyncHelper);
977 helper->mail_op = self;
979 /* Move/Copy folder */
980 tny_folder_copy_async (folder,
982 tny_folder_get_name (folder),
985 transfer_folder_status_cb,
991 /* ******************************************************************* */
992 /* ************************** MSG ACTIONS ************************* */
993 /* ******************************************************************* */
995 void modest_mail_operation_get_msg (ModestMailOperation *self,
997 GetMsgAsynUserCallback user_callback,
1000 GetMsgAsyncHelper *helper = NULL;
1002 ModestMailOperationPrivate *priv;
1004 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1005 g_return_if_fail (TNY_IS_HEADER (header));
1007 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1008 folder = tny_header_get_folder (header);
1010 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1012 /* Get message from folder */
1014 helper = g_slice_new0 (GetMsgAsyncHelper);
1015 helper->mail_op = self;
1016 helper->user_callback = user_callback;
1017 helper->pending_ops = 1;
1018 helper->user_data = user_data;
1020 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1022 g_object_unref (G_OBJECT (folder));
1024 /* Set status failed and set an error */
1025 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1026 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1027 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1028 _("Error trying to get a message. No folder found for header"));
1033 get_msg_cb (TnyFolder *folder,
1039 GetMsgAsyncHelper *helper = NULL;
1040 ModestMailOperation *self = NULL;
1041 ModestMailOperationPrivate *priv = NULL;
1043 helper = (GetMsgAsyncHelper *) user_data;
1044 g_return_if_fail (helper != NULL);
1045 self = helper->mail_op;
1046 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1047 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1049 helper->pending_ops--;
1051 /* Check errors and cancel */
1053 priv->error = g_error_copy (*error);
1054 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1058 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1059 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1060 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1061 _("Error trying to refresh the contents of %s"),
1062 tny_folder_get_name (folder));
1066 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1068 /* If user defined callback function was defined, call it */
1069 if (helper->user_callback) {
1070 helper->user_callback (priv->source, msg, helper->user_data);
1075 if (helper->pending_ops == 0) {
1076 g_slice_free (GetMsgAsyncHelper, helper);
1078 /* Notify about operation end */
1079 modest_mail_operation_notify_end (self);
1084 get_msg_status_cb (GObject *obj,
1088 GetMsgAsyncHelper *helper = NULL;
1089 ModestMailOperation *self;
1090 ModestMailOperationPrivate *priv;
1092 g_return_if_fail (status != NULL);
1093 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1095 helper = (GetMsgAsyncHelper *) user_data;
1096 g_return_if_fail (helper != NULL);
1098 /* Temporary FIX: useful when tinymail send us status
1099 information *after* calling the function callback */
1100 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1103 self = helper->mail_op;
1104 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1106 if ((status->position == 1) && (status->of_total == 100))
1112 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1115 /****************************************************/
1117 ModestMailOperation *mail_op;
1119 GetMsgAsynUserCallback user_callback;
1121 GDestroyNotify notify;
1125 * Used by get_msgs_full_thread to emit the "progress-changed" signal
1126 * from the main loop. We call it inside an idle call to achieve that
1129 notify_get_msgs_full_observers (gpointer data)
1131 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1133 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1135 g_object_unref (mail_op);
1141 GetMsgAsynUserCallback user_callback;
1145 } NotifyGetMsgsInfo;
1149 * Used by get_msgs_full_thread to call the user_callback for each
1150 * message that has been read
1153 notify_get_msgs_full (gpointer data)
1155 NotifyGetMsgsInfo *info;
1157 info = (NotifyGetMsgsInfo *) data;
1159 /* Call the user callback */
1160 info->user_callback (info->source, info->msg, info->user_data);
1162 g_slice_free (NotifyGetMsgsInfo, info);
1168 * Used by get_msgs_full_thread to free al the thread resources and to
1169 * call the destroy function for the passed user_data
1172 get_msgs_full_destroyer (gpointer data)
1174 GetFullMsgsInfo *info;
1176 info = (GetFullMsgsInfo *) data;
1179 info->notify (info->user_data);
1182 g_object_unref (info->headers);
1183 g_slice_free (GetFullMsgsInfo, info);
1189 get_msgs_full_thread (gpointer thr_user_data)
1191 GetFullMsgsInfo *info;
1192 ModestMailOperationPrivate *priv = NULL;
1193 TnyIterator *iter = NULL;
1195 info = (GetFullMsgsInfo *) thr_user_data;
1196 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1198 iter = tny_list_create_iterator (info->headers);
1199 while (!tny_iterator_is_done (iter)) {
1203 header = TNY_HEADER (tny_iterator_get_current (iter));
1204 folder = tny_header_get_folder (header);
1206 /* Get message from folder */
1209 /* The callback will call it per each header */
1210 msg = tny_folder_get_msg (folder, header, &(priv->error));
1215 /* notify progress */
1216 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1217 notify_get_msgs_full_observers,
1218 g_object_ref (info->mail_op), NULL);
1220 /* The callback is the responsible for
1221 freeing the message */
1222 if (info->user_callback) {
1223 NotifyGetMsgsInfo *info_notify;
1224 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1225 info_notify->user_callback = info->user_callback;
1226 info_notify->source = priv->source;
1227 info_notify->msg = msg;
1228 info_notify->user_data = info->user_data;
1229 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1230 notify_get_msgs_full,
1233 g_object_unref (msg);
1237 /* Set status failed and set an error */
1238 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1239 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1240 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1241 "Error trying to get a message. No folder found for header");
1243 g_object_unref (header);
1244 tny_iterator_next (iter);
1247 /* Notify about operation end */
1248 g_idle_add (notify_update_account_queue, info->mail_op);
1250 /* Free thread resources. Will be called after all previous idles */
1251 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1257 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1258 TnyList *header_list,
1259 GetMsgAsynUserCallback user_callback,
1261 GDestroyNotify notify)
1264 ModestMailOperationPrivate *priv = NULL;
1265 GetFullMsgsInfo *info = NULL;
1266 gboolean size_ok = TRUE;
1268 GError *error = NULL;
1269 const gint KB = 1024;
1271 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1273 /* Init mail operation */
1274 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1275 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1277 priv->total = tny_list_get_length(header_list);
1279 /* Get msg size limit */
1280 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1281 MODEST_CONF_MSG_SIZE_LIMIT,
1284 g_clear_error (&error);
1285 max_size = G_MAXINT;
1287 max_size = max_size * KB;
1290 /* Check message size limits. If there is only one message
1291 always retrieve it */
1292 if (tny_list_get_length (header_list) > 1) {
1295 iter = tny_list_create_iterator (header_list);
1296 while (!tny_iterator_is_done (iter) && size_ok) {
1297 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1298 if (tny_header_get_message_size (header) >= max_size)
1300 g_object_unref (header);
1301 tny_iterator_next (iter);
1303 g_object_unref (iter);
1307 /* Create the info */
1308 info = g_slice_new0 (GetFullMsgsInfo);
1309 info->mail_op = self;
1310 info->user_callback = user_callback;
1311 info->user_data = user_data;
1312 info->headers = g_object_ref (header_list);
1313 info->notify = notify;
1315 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1317 /* FIXME: the error msg is different for pop */
1318 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1319 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1320 _("emev_ni_ui_imap_msg_sizelimit_error"));
1321 /* Remove from queue and free resources */
1322 modest_mail_operation_notify_end (self);
1330 modest_mail_operation_remove_msg (ModestMailOperation *self,
1332 gboolean remove_to_trash)
1335 ModestMailOperationPrivate *priv;
1337 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1338 g_return_if_fail (TNY_IS_HEADER (header));
1340 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1341 folder = tny_header_get_folder (header);
1343 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1345 /* Delete or move to trash */
1346 if (remove_to_trash) {
1347 TnyFolder *trash_folder;
1348 TnyStoreAccount *store_account;
1350 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1351 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1352 TNY_FOLDER_TYPE_TRASH);
1357 headers = tny_simple_list_new ();
1358 tny_list_append (headers, G_OBJECT (header));
1359 g_object_unref (header);
1362 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1363 g_object_unref (headers);
1364 /* g_object_unref (trash_folder); */
1366 ModestMailOperationPrivate *priv;
1368 /* Set status failed and set an error */
1369 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1370 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1371 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1372 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1373 _("Error trying to delete a message. Trash folder not found"));
1376 g_object_unref (G_OBJECT (store_account));
1378 tny_folder_remove_msg (folder, header, &(priv->error));
1380 tny_folder_sync(folder, TRUE, &(priv->error));
1385 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1387 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1390 g_object_unref (G_OBJECT (folder));
1392 /* Notify about operation end */
1393 modest_mail_operation_notify_end (self);
1397 transfer_msgs_status_cb (GObject *obj,
1401 XFerMsgAsyncHelper *helper = NULL;
1402 ModestMailOperation *self;
1403 ModestMailOperationPrivate *priv;
1405 g_return_if_fail (status != NULL);
1406 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
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);
1414 if ((status->position == 1) && (status->of_total == 100))
1417 priv->done = status->position;
1418 priv->total = status->of_total;
1420 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1425 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1427 XFerMsgAsyncHelper *helper;
1428 ModestMailOperation *self;
1429 ModestMailOperationPrivate *priv;
1431 helper = (XFerMsgAsyncHelper *) user_data;
1432 self = helper->mail_op;
1434 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1437 priv->error = g_error_copy (*err);
1439 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1440 } else if (cancelled) {
1441 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1442 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1443 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1444 _("Error trying to refresh the contents of %s"),
1445 tny_folder_get_name (folder));
1448 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1451 /* If user defined callback function was defined, call it */
1452 if (helper->user_callback) {
1453 helper->user_callback (priv->source, helper->user_data);
1457 g_object_unref (helper->headers);
1458 g_object_unref (helper->dest_folder);
1459 g_object_unref (helper->mail_op);
1460 g_slice_free (XFerMsgAsyncHelper, helper);
1461 g_object_unref (folder);
1463 /* Notify about operation end */
1464 modest_mail_operation_notify_end (self);
1468 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1471 gboolean delete_original,
1472 XferMsgsAsynUserCallback user_callback,
1475 ModestMailOperationPrivate *priv;
1477 TnyFolder *src_folder;
1478 XFerMsgAsyncHelper *helper;
1481 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1482 g_return_if_fail (TNY_IS_LIST (headers));
1483 g_return_if_fail (TNY_IS_FOLDER (folder));
1485 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1488 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1490 /* Create the helper */
1491 helper = g_slice_new0 (XFerMsgAsyncHelper);
1492 helper->mail_op = g_object_ref(self);
1493 helper->dest_folder = g_object_ref(folder);
1494 helper->headers = g_object_ref(headers);
1495 helper->user_callback = user_callback;
1496 helper->user_data = user_data;
1498 /* Get source folder */
1499 iter = tny_list_create_iterator (headers);
1500 header = TNY_HEADER (tny_iterator_get_current (iter));
1501 src_folder = tny_header_get_folder (header);
1502 g_object_unref (header);
1503 g_object_unref (iter);
1505 /* Transfer messages */
1506 tny_folder_transfer_msgs_async (src_folder,
1511 transfer_msgs_status_cb,
1517 on_refresh_folder (TnyFolder *folder,
1522 ModestMailOperation *self;
1523 ModestMailOperationPrivate *priv;
1525 self = MODEST_MAIL_OPERATION (user_data);
1526 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1529 priv->error = g_error_copy (*error);
1530 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1535 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1536 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1537 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1538 _("Error trying to refresh the contents of %s"),
1539 tny_folder_get_name (folder));
1543 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1547 g_object_unref (folder);
1549 /* Notify about operation end */
1550 modest_mail_operation_notify_end (self);
1554 on_refresh_folder_status_update (GObject *obj,
1558 ModestMailOperation *self;
1559 ModestMailOperationPrivate *priv;
1561 g_return_if_fail (status != NULL);
1562 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1564 /* Temporary FIX: useful when tinymail send us status
1565 information *after* calling the function callback */
1566 if (!MODEST_IS_MAIL_OPERATION (user_data))
1569 self = MODEST_MAIL_OPERATION (user_data);
1570 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1572 priv->done = status->position;
1573 priv->total = status->of_total;
1575 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1579 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1582 ModestMailOperationPrivate *priv;
1584 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1586 /* Pick a reference */
1587 g_object_ref (folder);
1589 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1591 /* Refresh the folder. TODO: tinymail could issue a status
1592 updates before the callback call then this could happen. We
1593 must review the design */
1594 tny_folder_refresh_async (folder,
1596 on_refresh_folder_status_update,
1602 * It's used by the mail operation queue to notify the observers
1603 * attached to that signal that the operation finished. We need to use
1604 * that because tinymail does not give us the progress of a given
1605 * operation when it finishes (it directly calls the operation
1609 modest_mail_operation_notify_end (ModestMailOperation *self)
1611 /* Notify the observers about the mail opertation end */
1612 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1614 /* Notify the queue */
1615 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);