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-simple-list.h>
39 #include <tny-send-queue.h>
40 #include <tny-status.h>
41 #include <tny-folder-observer.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"
54 #include "modest-mail-operation.h"
58 /* 'private'/'protected' functions */
59 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
60 static void modest_mail_operation_init (ModestMailOperation *obj);
61 static void modest_mail_operation_finalize (GObject *obj);
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 static gboolean did_a_cancel = FALSE;
77 enum _ModestMailOperationSignals
79 PROGRESS_CHANGED_SIGNAL,
84 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
85 struct _ModestMailOperationPrivate {
91 ErrorCheckingUserCallback error_checking;
92 gpointer error_checking_user_data;
93 ModestMailOperationStatus status;
94 ModestMailOperationTypeOperation op_type;
97 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
98 MODEST_TYPE_MAIL_OPERATION, \
99 ModestMailOperationPrivate))
101 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
102 priv->status = new_status;\
105 typedef struct _GetMsgAsyncHelper {
106 ModestMailOperation *mail_op;
107 GetMsgAsyncUserCallback user_callback;
112 typedef struct _RefreshAsyncHelper {
113 ModestMailOperation *mail_op;
114 RefreshAsyncUserCallback user_callback;
116 } RefreshAsyncHelper;
118 typedef struct _XFerMsgAsyncHelper
120 ModestMailOperation *mail_op;
122 TnyFolder *dest_folder;
123 XferMsgsAsynUserCallback user_callback;
125 } XFerMsgAsyncHelper;
128 static GObjectClass *parent_class = NULL;
130 static guint signals[NUM_SIGNALS] = {0};
133 modest_mail_operation_get_type (void)
135 static GType my_type = 0;
137 static const GTypeInfo my_info = {
138 sizeof(ModestMailOperationClass),
139 NULL, /* base init */
140 NULL, /* base finalize */
141 (GClassInitFunc) modest_mail_operation_class_init,
142 NULL, /* class finalize */
143 NULL, /* class data */
144 sizeof(ModestMailOperation),
146 (GInstanceInitFunc) modest_mail_operation_init,
149 my_type = g_type_register_static (G_TYPE_OBJECT,
150 "ModestMailOperation",
157 modest_mail_operation_class_init (ModestMailOperationClass *klass)
159 GObjectClass *gobject_class;
160 gobject_class = (GObjectClass*) klass;
162 parent_class = g_type_class_peek_parent (klass);
163 gobject_class->finalize = modest_mail_operation_finalize;
165 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
168 * ModestMailOperation::progress-changed
169 * @self: the #MailOperation that emits the signal
170 * @user_data: user data set when the signal handler was connected
172 * Emitted when the progress of a mail operation changes
174 signals[PROGRESS_CHANGED_SIGNAL] =
175 g_signal_new ("progress-changed",
176 G_TYPE_FROM_CLASS (gobject_class),
178 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
180 g_cclosure_marshal_VOID__POINTER,
181 G_TYPE_NONE, 1, G_TYPE_POINTER);
186 modest_mail_operation_init (ModestMailOperation *obj)
188 ModestMailOperationPrivate *priv;
190 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
192 priv->account = NULL;
193 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
194 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
199 priv->error_checking = NULL;
200 priv->error_checking_user_data = NULL;
204 modest_mail_operation_finalize (GObject *obj)
206 ModestMailOperationPrivate *priv;
208 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
211 g_error_free (priv->error);
215 g_object_unref (priv->source);
219 g_object_unref (priv->account);
220 priv->account = NULL;
224 G_OBJECT_CLASS(parent_class)->finalize (obj);
228 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
231 ModestMailOperation *obj;
232 ModestMailOperationPrivate *priv;
234 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
235 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
237 priv->op_type = op_type;
239 priv->source = g_object_ref(source);
245 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
247 ErrorCheckingUserCallback error_handler,
250 ModestMailOperation *obj;
251 ModestMailOperationPrivate *priv;
253 obj = modest_mail_operation_new (op_type, source);
254 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
256 g_return_val_if_fail (error_handler != NULL, obj);
257 priv->error_checking = error_handler;
263 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
265 ModestMailOperationPrivate *priv;
267 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
268 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
270 if (priv->error_checking != NULL)
271 priv->error_checking (self, priv->error_checking_user_data);
275 ModestMailOperationTypeOperation
276 modest_mail_operation_get_type_operation (ModestMailOperation *self)
278 ModestMailOperationPrivate *priv;
280 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
282 return priv->op_type;
286 modest_mail_operation_is_mine (ModestMailOperation *self,
289 ModestMailOperationPrivate *priv;
291 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
292 if (priv->source == NULL) return FALSE;
294 return priv->source == me;
298 modest_mail_operation_get_source (ModestMailOperation *self)
300 ModestMailOperationPrivate *priv;
302 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
304 return g_object_ref (priv->source);
307 ModestMailOperationStatus
308 modest_mail_operation_get_status (ModestMailOperation *self)
310 ModestMailOperationPrivate *priv;
312 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
313 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
314 MODEST_MAIL_OPERATION_STATUS_INVALID);
316 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
321 modest_mail_operation_get_error (ModestMailOperation *self)
323 ModestMailOperationPrivate *priv;
325 g_return_val_if_fail (self, NULL);
326 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
328 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
333 modest_mail_operation_cancel (ModestMailOperation *self)
335 ModestMailOperationPrivate *priv;
337 if (!MODEST_IS_MAIL_OPERATION (self)) {
338 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
342 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
344 /* cancel current operation in account */
345 //tny_account_cancel (priv->account);
350 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
352 /* Notify about operation end */
353 modest_mail_operation_notify_end (self);
359 modest_mail_operation_get_task_done (ModestMailOperation *self)
361 ModestMailOperationPrivate *priv;
363 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
365 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
370 modest_mail_operation_get_task_total (ModestMailOperation *self)
372 ModestMailOperationPrivate *priv;
374 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
376 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
381 modest_mail_operation_is_finished (ModestMailOperation *self)
383 ModestMailOperationPrivate *priv;
384 gboolean retval = FALSE;
386 if (!MODEST_IS_MAIL_OPERATION (self)) {
387 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
391 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
393 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
394 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
395 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
396 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
406 modest_mail_operation_get_id (ModestMailOperation *self)
408 ModestMailOperationPrivate *priv;
410 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
412 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
417 modest_mail_operation_set_id (ModestMailOperation *self,
420 ModestMailOperationPrivate *priv;
422 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
424 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
429 * Creates an image of the current state of a mail operation, the
430 * caller must free it
432 static ModestMailOperationState *
433 modest_mail_operation_clone_state (ModestMailOperation *self)
435 ModestMailOperationState *state;
436 ModestMailOperationPrivate *priv;
438 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
440 state = g_slice_new (ModestMailOperationState);
442 state->status = priv->status;
443 state->op_type = priv->op_type;
444 state->done = priv->done;
445 state->total = priv->total;
446 state->finished = modest_mail_operation_is_finished (self);
451 /* ******************************************************************* */
452 /* ************************** SEND ACTIONS ************************* */
453 /* ******************************************************************* */
456 modest_mail_operation_send_mail (ModestMailOperation *self,
457 TnyTransportAccount *transport_account,
460 TnySendQueue *send_queue = NULL;
461 ModestMailOperationPrivate *priv;
463 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
464 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
465 g_return_if_fail (TNY_IS_MSG (msg));
467 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
469 /* Get account and set it into mail_operation */
470 priv->account = g_object_ref (transport_account);
472 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
473 if (!TNY_IS_SEND_QUEUE(send_queue)) {
474 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
475 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
476 "modest: could not find send queue for account\n");
478 tny_send_queue_add (send_queue, msg, &(priv->error));
481 /* Notify about operation end */
482 modest_mail_operation_notify_end (self);
486 modest_mail_operation_send_new_mail (ModestMailOperation *self,
487 TnyTransportAccount *transport_account,
489 const gchar *from, const gchar *to,
490 const gchar *cc, const gchar *bcc,
491 const gchar *subject, const gchar *plain_body,
492 const gchar *html_body,
493 const GList *attachments_list,
494 TnyHeaderFlags priority_flags)
496 TnyMsg *new_msg = NULL;
497 TnyFolder *folder = NULL;
498 TnyHeader *header = NULL;
499 ModestMailOperationPrivate *priv = NULL;
501 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
502 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
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);
509 /* Check parametters */
511 /* Set status failed and set an error */
512 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
513 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
514 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
515 _("Error trying to send a mail. You need to set at least one recipient"));
519 if (html_body == NULL) {
520 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
522 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
525 g_printerr ("modest: failed to create a new msg\n");
529 /* Set priority flags in message */
530 header = tny_msg_get_header (new_msg);
531 if (priority_flags != 0)
532 tny_header_set_flags (header, priority_flags);
534 /* Call mail operation */
535 modest_mail_operation_send_mail (self, transport_account, new_msg);
537 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
539 if (draft_msg != NULL) {
540 header = tny_msg_get_header (draft_msg);
541 /* Note: This can fail (with a warning) if the message is not really already in a folder,
542 * because this function requires it to have a UID. */
543 tny_folder_remove_msg (folder, header, NULL);
544 g_object_unref (header);
549 g_object_unref (G_OBJECT (new_msg));
553 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
554 TnyTransportAccount *transport_account,
556 const gchar *from, const gchar *to,
557 const gchar *cc, const gchar *bcc,
558 const gchar *subject, const gchar *plain_body,
559 const gchar *html_body,
560 const GList *attachments_list,
561 TnyHeaderFlags priority_flags)
564 TnyFolder *folder = NULL;
565 TnyHeader *header = NULL;
566 ModestMailOperationPrivate *priv = NULL;
568 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
569 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
571 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
573 /* Get account and set it into mail_operation */
574 priv->account = g_object_ref (transport_account);
576 if (html_body == NULL) {
577 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
579 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
582 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
583 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
584 "modest: failed to create a new msg\n");
588 /* add priority flags */
589 header = tny_msg_get_header (msg);
590 tny_header_set_flags (header, priority_flags);
592 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
594 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
595 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
596 "modest: failed to create a new msg\n");
600 if (draft_msg != NULL) {
601 header = tny_msg_get_header (draft_msg);
602 tny_folder_remove_msg (folder, header, NULL);
603 g_object_unref (header);
606 tny_folder_add_msg (folder, msg, &(priv->error));
612 g_object_unref (G_OBJECT(msg));
614 g_object_unref (G_OBJECT(folder));
616 modest_mail_operation_notify_end (self);
621 ModestMailOperation *mail_op;
622 TnyStoreAccount *account;
623 TnyTransportAccount *transport_account;
626 gchar *retrieve_type;
629 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
630 /* We use this folder observer to track the headers that have been
631 * added to a folder */
634 TnyList *new_headers;
635 } InternalFolderObserver;
639 } InternalFolderObserverClass;
641 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
643 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
644 internal_folder_observer,
646 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
650 foreach_add_item (gpointer header, gpointer user_data)
652 /* printf("DEBUG: %s: header subject=%s\n",
653 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
655 tny_list_prepend (TNY_LIST (user_data),
656 g_object_ref (G_OBJECT (header)));
659 /* This is the method that looks for new messages in a folder */
661 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
663 InternalFolderObserver *derived = (InternalFolderObserver *)self;
665 TnyFolderChangeChanged changed;
667 changed = tny_folder_change_get_changed (change);
669 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
672 /* Get added headers */
673 list = tny_simple_list_new ();
674 tny_folder_change_get_added_headers (change, list);
676 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
677 * __FUNCTION__, tny_list_get_length(list));
680 /* Add them to the folder observer */
681 tny_list_foreach (list, foreach_add_item,
682 derived->new_headers);
684 g_object_unref (G_OBJECT (list));
689 internal_folder_observer_init (InternalFolderObserver *self)
691 self->new_headers = tny_simple_list_new ();
694 internal_folder_observer_finalize (GObject *object)
696 InternalFolderObserver *self;
698 self = (InternalFolderObserver *) object;
699 g_object_unref (self->new_headers);
701 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
704 tny_folder_observer_init (TnyFolderObserverIface *iface)
706 iface->update_func = internal_folder_observer_update;
709 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
711 GObjectClass *object_class;
713 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
714 object_class = (GObjectClass*) klass;
715 object_class->finalize = internal_folder_observer_finalize;
721 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
724 TnyList *folders = tny_simple_list_new ();
726 tny_folder_store_get_folders (store, folders, query, NULL);
727 iter = tny_list_create_iterator (folders);
729 while (!tny_iterator_is_done (iter)) {
731 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
733 tny_list_prepend (all_folders, G_OBJECT (folder));
734 recurse_folders (folder, query, all_folders);
735 g_object_unref (G_OBJECT (folder));
737 tny_iterator_next (iter);
739 g_object_unref (G_OBJECT (iter));
740 g_object_unref (G_OBJECT (folders));
744 * Issues the "progress-changed" signal. The timer won't be removed,
745 * so you must call g_source_remove to stop the signal emission
748 idle_notify_progress (gpointer data)
750 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
751 ModestMailOperationState *state;
753 state = modest_mail_operation_clone_state (mail_op);
754 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
755 g_slice_free (ModestMailOperationState, state);
761 * Issues the "progress-changed" signal and removes the timer. It uses
762 * a lock to ensure that the progress information of the mail
763 * operation is not modified while there are notifications pending
766 idle_notify_progress_once (gpointer data)
770 pair = (ModestPair *) data;
772 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
774 /* Free the state and the reference to the mail operation */
775 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
776 g_object_unref (pair->first);
782 * Used by update_account_thread to notify the queue from the main
783 * loop. We call it inside an idle call to achieve that
786 notify_update_account_queue (gpointer data)
788 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
789 ModestMailOperationPrivate *priv = NULL;
791 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
793 modest_mail_operation_notify_end (mail_op);
794 g_object_unref (mail_op);
800 compare_headers_by_date (gconstpointer a,
803 TnyHeader **header1, **header2;
806 header1 = (TnyHeader **) a;
807 header2 = (TnyHeader **) b;
809 sent1 = tny_header_get_date_sent (*header1);
810 sent2 = tny_header_get_date_sent (*header2);
812 /* We want the most recent ones (greater time_t) at the
821 set_last_updated_idle (gpointer data)
823 /* It does not matter if the time is not exactly the same than
824 the time when this idle was called, it's just an
825 approximation and it won't be very different */
826 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
828 MODEST_ACCOUNT_LAST_UPDATED,
836 update_account_thread (gpointer thr_user_data)
838 UpdateAccountInfo *info;
839 TnyList *all_folders = NULL;
840 GPtrArray *new_headers;
841 TnyIterator *iter = NULL;
842 TnyFolderStoreQuery *query = NULL;
843 ModestMailOperationPrivate *priv;
844 ModestTnySendQueue *send_queue;
847 info = (UpdateAccountInfo *) thr_user_data;
848 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
850 /* Get account and set it into mail_operation */
851 priv->account = g_object_ref (info->account);
854 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
855 * show any updates unless we do that
857 if (TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
858 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
860 /* Get all the folders. We can do it synchronously because
861 we're already running in a different thread than the UI */
862 all_folders = tny_simple_list_new ();
863 query = tny_folder_store_query_new ();
864 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
865 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
870 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
874 iter = tny_list_create_iterator (all_folders);
875 while (!tny_iterator_is_done (iter)) {
876 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
878 recurse_folders (folder, query, all_folders);
879 tny_iterator_next (iter);
881 g_object_unref (G_OBJECT (iter));
883 /* Update status and notify. We need to call the notification
884 with a source function in order to call it from the main
885 loop. We need that in order not to get into trouble with
886 Gtk+. We use a timeout in order to provide more status
887 information, because the sync tinymail call does not
888 provide it for the moment */
889 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
891 /* Refresh folders */
892 new_headers = g_ptr_array_new ();
893 iter = tny_list_create_iterator (all_folders);
895 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
897 InternalFolderObserver *observer;
898 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
900 /* Refresh the folder */
901 /* Our observer receives notification of new emails during folder refreshes,
902 * so we can use observer->new_headers.
903 * TODO: This does not seem to be providing accurate numbers.
904 * Possibly the observer is notified asynchronously.
906 observer = g_object_new (internal_folder_observer_get_type (), NULL);
907 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
909 /* This gets the status information (headers) from the server.
910 * We use the blocking version, because we are already in a separate
914 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
915 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
918 /* If the retrieve type is full messages, refresh and get the messages */
919 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
921 iter = tny_list_create_iterator (observer->new_headers);
922 while (!tny_iterator_is_done (iter)) {
923 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
924 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
925 * __FUNCTION__, tny_account_get_id (priv->account),
926 * tny_header_get_subject (header));
929 /* Apply per-message size limits */
930 if (tny_header_get_message_size (header) < info->max_size)
931 g_ptr_array_add (new_headers, g_object_ref (header));
933 g_object_unref (header);
934 tny_iterator_next (iter);
936 g_object_unref (iter);
939 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
940 g_object_unref (observer);
944 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
946 g_object_unref (G_OBJECT (folder));
947 tny_iterator_next (iter);
950 did_a_cancel = FALSE;
952 g_object_unref (G_OBJECT (iter));
953 g_source_remove (timeout);
955 if (new_headers->len > 0) {
959 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
961 /* Apply message count limit */
962 /* If the number of messages exceeds the maximum, ask the
963 * user to download them all,
964 * as per the UI spec "Retrieval Limits" section in 4.4:
966 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
967 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
968 if (new_headers->len > info->retrieve_limit) {
969 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
970 * with 'Get all' and 'Newest only' buttons. */
971 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
972 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
973 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
974 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
975 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
980 priv->total = MIN (new_headers->len, info->retrieve_limit);
981 while (msg_num < priv->total) {
983 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
984 TnyFolder *folder = tny_header_get_folder (header);
985 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
986 ModestMailOperationState *state;
990 /* We can not just use the mail operation because the
991 values of done and total could change before the
993 state = modest_mail_operation_clone_state (info->mail_op);
994 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
995 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
996 pair, (GDestroyNotify) modest_pair_free);
998 g_object_unref (msg);
999 g_object_unref (folder);
1003 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1004 g_ptr_array_free (new_headers, FALSE);
1008 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1011 if (priv->account != NULL)
1012 g_object_unref (priv->account);
1013 priv->account = g_object_ref (info->transport_account);
1015 send_queue = modest_runtime_get_send_queue (info->transport_account);
1017 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
1018 modest_tny_send_queue_try_to_send (send_queue);
1019 g_source_remove (timeout);
1021 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1022 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1023 "cannot create a send queue for %s\n",
1024 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1025 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1028 /* Check if the operation was a success */
1030 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1032 /* Update the last updated key */
1033 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1034 set_last_updated_idle,
1035 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1036 (GDestroyNotify) g_free);
1040 /* Notify about operation end. Note that the info could be
1041 freed before this idle happens, but the mail operation will
1043 g_idle_add (notify_update_account_queue, info->mail_op);
1046 g_object_unref (query);
1047 g_object_unref (all_folders);
1048 g_object_unref (info->account);
1049 g_object_unref (info->transport_account);
1050 g_free (info->retrieve_type);
1051 g_slice_free (UpdateAccountInfo, info);
1057 modest_mail_operation_update_account (ModestMailOperation *self,
1058 const gchar *account_name)
1061 UpdateAccountInfo *info;
1062 ModestMailOperationPrivate *priv;
1063 ModestAccountMgr *mgr;
1064 TnyStoreAccount *modest_account;
1065 TnyTransportAccount *transport_account;
1067 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1068 g_return_val_if_fail (account_name, FALSE);
1070 /* Make sure that we have a connection, and request one
1072 * TODO: Is there some way to trigger this for every attempt to
1073 * use the network? */
1074 if (!modest_platform_connect_and_wait(NULL))
1077 /* Init mail operation. Set total and done to 0, and do not
1078 update them, this way the progress objects will know that
1079 we have no clue about the number of the objects */
1080 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1083 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1085 /* Get the Modest account */
1086 modest_account = (TnyStoreAccount *)
1087 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1089 TNY_ACCOUNT_TYPE_STORE);
1091 if (!modest_account) {
1092 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1093 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1094 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1095 "cannot get tny store account for %s\n", account_name);
1096 modest_mail_operation_notify_end (self);
1102 /* Get the transport account, we can not do it in the thread
1103 due to some problems with dbus */
1104 transport_account = (TnyTransportAccount *)
1105 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1107 if (!transport_account) {
1108 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1109 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1110 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1111 "cannot get tny transport account for %s\n", account_name);
1112 modest_mail_operation_notify_end (self);
1117 /* Create the helper object */
1118 info = g_slice_new (UpdateAccountInfo);
1119 info->mail_op = self;
1120 info->account = modest_account;
1121 info->transport_account = transport_account;
1123 /* Get the message size limit */
1124 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1125 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1126 if (info->max_size == 0)
1127 info->max_size = G_MAXINT;
1129 info->max_size = info->max_size * KB;
1131 /* Get per-account retrieval type */
1132 mgr = modest_runtime_get_account_mgr ();
1133 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1134 MODEST_ACCOUNT_RETRIEVE, FALSE);
1136 /* Get per-account message amount retrieval limit */
1137 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1138 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1139 if (info->retrieve_limit == 0)
1140 info->retrieve_limit = G_MAXINT;
1142 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1144 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1149 /* ******************************************************************* */
1150 /* ************************** STORE ACTIONS ************************* */
1151 /* ******************************************************************* */
1155 modest_mail_operation_create_folder (ModestMailOperation *self,
1156 TnyFolderStore *parent,
1159 ModestMailOperationPrivate *priv;
1160 TnyFolder *new_folder = NULL;
1162 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1163 g_return_val_if_fail (name, NULL);
1165 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1168 if (TNY_IS_FOLDER (parent)) {
1169 /* Check folder rules */
1170 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1171 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1172 /* Set status failed and set an error */
1173 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1174 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1175 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1176 _("mail_in_ui_folder_create_error"));
1181 /* Create the folder */
1182 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1183 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1185 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1188 /* Notify about operation end */
1189 modest_mail_operation_notify_end (self);
1195 modest_mail_operation_remove_folder (ModestMailOperation *self,
1197 gboolean remove_to_trash)
1199 TnyAccount *account;
1200 ModestMailOperationPrivate *priv;
1201 ModestTnyFolderRules rules;
1203 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1204 g_return_if_fail (TNY_IS_FOLDER (folder));
1206 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1208 /* Check folder rules */
1209 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1210 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1211 /* Set status failed and set an error */
1212 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1213 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1214 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1215 _("mail_in_ui_folder_delete_error"));
1219 /* Get the account */
1220 account = modest_tny_folder_get_account (folder);
1221 priv->account = g_object_ref(account);
1223 /* Delete folder or move to trash */
1224 if (remove_to_trash) {
1225 TnyFolder *trash_folder = NULL;
1226 trash_folder = modest_tny_account_get_special_folder (account,
1227 TNY_FOLDER_TYPE_TRASH);
1228 /* TODO: error_handling */
1229 modest_mail_operation_xfer_folder (self, folder,
1230 TNY_FOLDER_STORE (trash_folder), TRUE);
1232 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1234 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1235 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1238 g_object_unref (G_OBJECT (parent));
1240 g_object_unref (G_OBJECT (account));
1243 /* Notify about operation end */
1244 modest_mail_operation_notify_end (self);
1248 transfer_folder_status_cb (GObject *obj,
1252 ModestMailOperation *self;
1253 ModestMailOperationPrivate *priv;
1254 ModestMailOperationState *state;
1256 g_return_if_fail (status != NULL);
1257 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1259 self = MODEST_MAIL_OPERATION (user_data);
1260 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1262 if ((status->position == 1) && (status->of_total == 100))
1265 priv->done = status->position;
1266 priv->total = status->of_total;
1268 state = modest_mail_operation_clone_state (self);
1269 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1270 g_slice_free (ModestMailOperationState, state);
1275 transfer_folder_cb (TnyFolder *folder,
1276 TnyFolderStore *into,
1278 TnyFolder *new_folder, GError **err,
1281 ModestMailOperation *self = NULL;
1282 ModestMailOperationPrivate *priv = NULL;
1284 self = MODEST_MAIL_OPERATION (user_data);
1286 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1289 priv->error = g_error_copy (*err);
1291 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1292 } else if (cancelled) {
1293 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1294 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1295 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1296 _("Transference of %s was cancelled."),
1297 tny_folder_get_name (folder));
1300 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1304 g_object_unref (folder);
1305 g_object_unref (into);
1306 if (new_folder != NULL)
1307 g_object_unref (new_folder);
1309 /* Notify about operation end */
1310 modest_mail_operation_notify_end (self);
1314 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1316 TnyFolderStore *parent,
1317 gboolean delete_original)
1319 ModestMailOperationPrivate *priv = NULL;
1320 ModestTnyFolderRules parent_rules, rules;
1322 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1323 g_return_if_fail (TNY_IS_FOLDER (folder));
1324 g_return_if_fail (TNY_IS_FOLDER (parent));
1326 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1328 /* Get account and set it into mail_operation */
1329 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1330 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1332 /* Get folder rules */
1333 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1334 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1336 if (!TNY_IS_FOLDER_STORE (parent)) {
1340 /* The moveable restriction is applied also to copy operation */
1341 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1342 /* Set status failed and set an error */
1343 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1344 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1345 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1346 _("mail_in_ui_folder_move_target_error"));
1348 /* Notify the queue */
1349 modest_mail_operation_notify_end (self);
1350 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1351 /* Set status failed and set an error */
1352 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1353 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1354 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1355 _("FIXME: parent folder does not accept new folders"));
1357 /* Notify the queue */
1358 modest_mail_operation_notify_end (self);
1360 /* Pick references for async calls */
1361 g_object_ref (folder);
1362 g_object_ref (parent);
1364 /* Move/Copy folder */
1365 tny_folder_copy_async (folder,
1367 tny_folder_get_name (folder),
1370 transfer_folder_status_cb,
1376 modest_mail_operation_rename_folder (ModestMailOperation *self,
1380 ModestMailOperationPrivate *priv;
1381 ModestTnyFolderRules rules;
1383 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1384 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1385 g_return_if_fail (name);
1387 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1389 /* Get account and set it into mail_operation */
1390 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1392 /* Check folder rules */
1393 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1394 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1395 /* Set status failed and set an error */
1396 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1397 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1398 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1399 _("FIXME: unable to rename"));
1401 /* Notify about operation end */
1402 modest_mail_operation_notify_end (self);
1404 /* Rename. Camel handles folder subscription/unsubscription */
1405 TnyFolderStore *into;
1407 into = tny_folder_get_folder_store (folder);
1408 tny_folder_copy_async (folder, into, name, TRUE,
1410 transfer_folder_status_cb,
1413 g_object_unref (into);
1418 /* ******************************************************************* */
1419 /* ************************** MSG ACTIONS ************************* */
1420 /* ******************************************************************* */
1422 void modest_mail_operation_get_msg (ModestMailOperation *self,
1424 GetMsgAsyncUserCallback user_callback,
1427 GetMsgAsyncHelper *helper = NULL;
1429 ModestMailOperationPrivate *priv;
1431 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1432 g_return_if_fail (TNY_IS_HEADER (header));
1434 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1435 folder = tny_header_get_folder (header);
1437 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1439 /* Get message from folder */
1441 /* Get account and set it into mail_operation */
1442 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1444 helper = g_slice_new0 (GetMsgAsyncHelper);
1445 helper->mail_op = self;
1446 helper->user_callback = user_callback;
1447 helper->pending_ops = 1;
1448 helper->user_data = user_data;
1450 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1452 g_object_unref (G_OBJECT (folder));
1454 /* Set status failed and set an error */
1455 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1456 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1457 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1458 _("Error trying to get a message. No folder found for header"));
1460 /* Notify the queue */
1461 modest_mail_operation_notify_end (self);
1466 get_msg_cb (TnyFolder *folder,
1472 GetMsgAsyncHelper *helper = NULL;
1473 ModestMailOperation *self = NULL;
1474 ModestMailOperationPrivate *priv = NULL;
1476 helper = (GetMsgAsyncHelper *) user_data;
1477 g_return_if_fail (helper != NULL);
1478 self = helper->mail_op;
1479 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1480 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1482 helper->pending_ops--;
1484 /* Check errors and cancel */
1486 priv->error = g_error_copy (*error);
1487 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1491 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1492 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1493 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1494 _("Error trying to refresh the contents of %s"),
1495 tny_folder_get_name (folder));
1499 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1501 /* If user defined callback function was defined, call it */
1502 if (helper->user_callback) {
1503 helper->user_callback (self, NULL, msg, helper->user_data);
1508 if (helper->pending_ops == 0) {
1509 g_slice_free (GetMsgAsyncHelper, helper);
1511 /* Notify about operation end */
1512 modest_mail_operation_notify_end (self);
1517 get_msg_status_cb (GObject *obj,
1521 GetMsgAsyncHelper *helper = NULL;
1522 ModestMailOperation *self;
1523 ModestMailOperationPrivate *priv;
1524 ModestMailOperationState *state;
1526 g_return_if_fail (status != NULL);
1527 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1529 helper = (GetMsgAsyncHelper *) user_data;
1530 g_return_if_fail (helper != NULL);
1532 self = helper->mail_op;
1533 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1535 if ((status->position == 1) && (status->of_total == 100))
1541 state = modest_mail_operation_clone_state (self);
1542 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1543 g_slice_free (ModestMailOperationState, state);
1546 /****************************************************/
1548 ModestMailOperation *mail_op;
1550 GetMsgAsyncUserCallback user_callback;
1552 GDestroyNotify notify;
1556 GetMsgAsyncUserCallback user_callback;
1560 ModestMailOperation *mail_op;
1561 } NotifyGetMsgsInfo;
1565 * Used by get_msgs_full_thread to call the user_callback for each
1566 * message that has been read
1569 notify_get_msgs_full (gpointer data)
1571 NotifyGetMsgsInfo *info;
1573 info = (NotifyGetMsgsInfo *) data;
1575 /* Call the user callback */
1576 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1578 g_slice_free (NotifyGetMsgsInfo, info);
1584 * Used by get_msgs_full_thread to free al the thread resources and to
1585 * call the destroy function for the passed user_data
1588 get_msgs_full_destroyer (gpointer data)
1590 GetFullMsgsInfo *info;
1592 info = (GetFullMsgsInfo *) data;
1595 info->notify (info->user_data);
1598 g_object_unref (info->headers);
1599 g_slice_free (GetFullMsgsInfo, info);
1605 get_msgs_full_thread (gpointer thr_user_data)
1607 GetFullMsgsInfo *info;
1608 ModestMailOperationPrivate *priv = NULL;
1609 TnyIterator *iter = NULL;
1611 info = (GetFullMsgsInfo *) thr_user_data;
1612 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1614 iter = tny_list_create_iterator (info->headers);
1615 while (!tny_iterator_is_done (iter)) {
1619 header = TNY_HEADER (tny_iterator_get_current (iter));
1620 folder = tny_header_get_folder (header);
1622 /* Get message from folder */
1625 /* The callback will call it per each header */
1626 msg = tny_folder_get_msg (folder, header, &(priv->error));
1629 ModestMailOperationState *state;
1634 /* notify progress */
1635 state = modest_mail_operation_clone_state (info->mail_op);
1636 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1637 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1638 pair, (GDestroyNotify) modest_pair_free);
1640 /* The callback is the responsible for
1641 freeing the message */
1642 if (info->user_callback) {
1643 NotifyGetMsgsInfo *info_notify;
1644 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1645 info_notify->user_callback = info->user_callback;
1646 info_notify->mail_op = info->mail_op;
1647 info_notify->header = g_object_ref (header);
1648 info_notify->msg = g_object_ref (msg);
1649 info_notify->user_data = info->user_data;
1650 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1651 notify_get_msgs_full,
1654 g_object_unref (msg);
1657 /* Set status failed and set an error */
1658 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1659 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1660 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1661 "Error trying to get a message. No folder found for header");
1663 g_object_unref (header);
1664 tny_iterator_next (iter);
1667 /* Set operation status */
1668 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1669 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1671 /* Notify about operation end */
1672 g_idle_add (notify_update_account_queue, info->mail_op);
1674 /* Free thread resources. Will be called after all previous idles */
1675 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1681 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1682 TnyList *header_list,
1683 GetMsgAsyncUserCallback user_callback,
1685 GDestroyNotify notify)
1687 TnyHeader *header = NULL;
1688 TnyFolder *folder = NULL;
1690 ModestMailOperationPrivate *priv = NULL;
1691 GetFullMsgsInfo *info = NULL;
1692 gboolean size_ok = TRUE;
1694 TnyIterator *iter = NULL;
1696 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1698 /* Init mail operation */
1699 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1700 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1702 priv->total = tny_list_get_length(header_list);
1704 /* Get account and set it into mail_operation */
1705 if (tny_list_get_length (header_list) >= 1) {
1706 iter = tny_list_create_iterator (header_list);
1707 header = TNY_HEADER (tny_iterator_get_current (iter));
1708 folder = tny_header_get_folder (header);
1709 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1710 g_object_unref (header);
1711 g_object_unref (folder);
1713 if (tny_list_get_length (header_list) == 1) {
1714 g_object_unref (iter);
1719 /* Get msg size limit */
1720 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1721 MODEST_CONF_MSG_SIZE_LIMIT,
1724 g_clear_error (&(priv->error));
1725 max_size = G_MAXINT;
1727 max_size = max_size * KB;
1730 /* Check message size limits. If there is only one message
1731 always retrieve it */
1733 while (!tny_iterator_is_done (iter) && size_ok) {
1734 header = TNY_HEADER (tny_iterator_get_current (iter));
1735 if (tny_header_get_message_size (header) >= max_size)
1737 g_object_unref (header);
1738 tny_iterator_next (iter);
1740 g_object_unref (iter);
1744 /* Create the info */
1745 info = g_slice_new0 (GetFullMsgsInfo);
1746 info->mail_op = self;
1747 info->user_callback = user_callback;
1748 info->user_data = user_data;
1749 info->headers = g_object_ref (header_list);
1750 info->notify = notify;
1752 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1754 /* Set status failed and set an error */
1755 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1756 /* FIXME: the error msg is different for pop */
1757 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1758 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1759 _("emev_ni_ui_imap_msg_size_exceed_error"));
1760 /* Remove from queue and free resources */
1761 modest_mail_operation_notify_end (self);
1769 modest_mail_operation_remove_msg (ModestMailOperation *self,
1771 gboolean remove_to_trash)
1774 ModestMailOperationPrivate *priv;
1776 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1777 g_return_if_fail (TNY_IS_HEADER (header));
1779 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1780 folder = tny_header_get_folder (header);
1782 /* Get account and set it into mail_operation */
1783 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1785 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1787 /* Delete or move to trash */
1788 if (remove_to_trash) {
1789 TnyFolder *trash_folder;
1790 TnyStoreAccount *store_account;
1792 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1793 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1794 TNY_FOLDER_TYPE_TRASH);
1799 headers = tny_simple_list_new ();
1800 tny_list_append (headers, G_OBJECT (header));
1801 g_object_unref (header);
1804 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1805 g_object_unref (headers);
1806 /* g_object_unref (trash_folder); */
1808 ModestMailOperationPrivate *priv;
1810 /* Set status failed and set an error */
1811 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1812 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1813 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1814 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1815 _("Error trying to delete a message. Trash folder not found"));
1818 g_object_unref (G_OBJECT (store_account));
1820 tny_folder_remove_msg (folder, header, &(priv->error));
1822 tny_folder_sync(folder, TRUE, &(priv->error));
1827 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1829 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1832 g_object_unref (G_OBJECT (folder));
1834 /* Notify about operation end */
1835 modest_mail_operation_notify_end (self);
1839 transfer_msgs_status_cb (GObject *obj,
1843 XFerMsgAsyncHelper *helper = NULL;
1844 ModestMailOperation *self;
1845 ModestMailOperationPrivate *priv;
1846 ModestMailOperationState *state;
1849 g_return_if_fail (status != NULL);
1850 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1852 helper = (XFerMsgAsyncHelper *) user_data;
1853 g_return_if_fail (helper != NULL);
1855 self = helper->mail_op;
1856 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1858 if ((status->position == 1) && (status->of_total == 100))
1861 priv->done = status->position;
1862 priv->total = status->of_total;
1864 state = modest_mail_operation_clone_state (self);
1865 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1866 g_slice_free (ModestMailOperationState, state);
1871 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1873 XFerMsgAsyncHelper *helper;
1874 ModestMailOperation *self;
1875 ModestMailOperationPrivate *priv;
1877 helper = (XFerMsgAsyncHelper *) user_data;
1878 self = helper->mail_op;
1880 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1883 priv->error = g_error_copy (*err);
1885 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1886 } else if (cancelled) {
1887 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1888 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1889 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1890 _("Error trying to refresh the contents of %s"),
1891 tny_folder_get_name (folder));
1894 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1897 /* If user defined callback function was defined, call it */
1898 if (helper->user_callback) {
1899 helper->user_callback (priv->source, helper->user_data);
1903 g_object_unref (helper->headers);
1904 g_object_unref (helper->dest_folder);
1905 g_object_unref (helper->mail_op);
1906 g_slice_free (XFerMsgAsyncHelper, helper);
1907 g_object_unref (folder);
1909 /* Notify about operation end */
1910 modest_mail_operation_notify_end (self);
1914 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1917 gboolean delete_original,
1918 XferMsgsAsynUserCallback user_callback,
1921 ModestMailOperationPrivate *priv;
1923 TnyFolder *src_folder;
1924 XFerMsgAsyncHelper *helper;
1926 ModestTnyFolderRules rules;
1928 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1929 g_return_if_fail (TNY_IS_LIST (headers));
1930 g_return_if_fail (TNY_IS_FOLDER (folder));
1932 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1935 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1937 /* Apply folder rules */
1938 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1940 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1941 /* Set status failed and set an error */
1942 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1943 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1944 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1945 _("FIXME: folder does not accept msgs"));
1946 /* Notify the queue */
1947 modest_mail_operation_notify_end (self);
1951 /* Create the helper */
1952 helper = g_slice_new0 (XFerMsgAsyncHelper);
1953 helper->mail_op = g_object_ref(self);
1954 helper->dest_folder = g_object_ref(folder);
1955 helper->headers = g_object_ref(headers);
1956 helper->user_callback = user_callback;
1957 helper->user_data = user_data;
1959 /* Get source folder */
1960 iter = tny_list_create_iterator (headers);
1961 header = TNY_HEADER (tny_iterator_get_current (iter));
1962 src_folder = tny_header_get_folder (header);
1963 g_object_unref (header);
1964 g_object_unref (iter);
1966 /* Get account and set it into mail_operation */
1967 priv->account = modest_tny_folder_get_account (src_folder);
1969 /* Transfer messages */
1970 tny_folder_transfer_msgs_async (src_folder,
1975 transfer_msgs_status_cb,
1981 on_refresh_folder (TnyFolder *folder,
1986 RefreshAsyncHelper *helper = NULL;
1987 ModestMailOperation *self = NULL;
1988 ModestMailOperationPrivate *priv = NULL;
1990 helper = (RefreshAsyncHelper *) user_data;
1991 self = helper->mail_op;
1992 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1995 priv->error = g_error_copy (*error);
1996 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2001 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2002 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2003 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2004 _("Error trying to refresh the contents of %s"),
2005 tny_folder_get_name (folder));
2009 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2012 /* Call user defined callback, if it exists */
2013 if (helper->user_callback)
2014 helper->user_callback (priv->source, folder, helper->user_data);
2017 g_object_unref (helper->mail_op);
2018 g_slice_free (RefreshAsyncHelper, helper);
2019 g_object_unref (folder);
2021 /* Notify about operation end */
2022 modest_mail_operation_notify_end (self);
2026 on_refresh_folder_status_update (GObject *obj,
2030 RefreshAsyncHelper *helper = NULL;
2031 ModestMailOperation *self = NULL;
2032 ModestMailOperationPrivate *priv = NULL;
2033 ModestMailOperationState *state;
2035 g_return_if_fail (user_data != NULL);
2036 g_return_if_fail (status != NULL);
2037 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2039 helper = (RefreshAsyncHelper *) user_data;
2040 self = helper->mail_op;
2041 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2043 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2045 priv->done = status->position;
2046 priv->total = status->of_total;
2048 state = modest_mail_operation_clone_state (self);
2049 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2050 g_slice_free (ModestMailOperationState, state);
2054 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2056 RefreshAsyncUserCallback user_callback,
2059 ModestMailOperationPrivate *priv = NULL;
2060 RefreshAsyncHelper *helper = NULL;
2062 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2064 /* Pick a reference */
2065 g_object_ref (folder);
2067 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2069 /* Get account and set it into mail_operation */
2070 priv->account = modest_tny_folder_get_account (folder);
2072 /* Create the helper */
2073 helper = g_slice_new0 (RefreshAsyncHelper);
2074 helper->mail_op = g_object_ref(self);
2075 helper->user_callback = user_callback;
2076 helper->user_data = user_data;
2078 /* Refresh the folder. TODO: tinymail could issue a status
2079 updates before the callback call then this could happen. We
2080 must review the design */
2081 tny_folder_refresh_async (folder,
2083 on_refresh_folder_status_update,
2089 * It's used by the mail operation queue to notify the observers
2090 * attached to that signal that the operation finished. We need to use
2091 * that because tinymail does not give us the progress of a given
2092 * operation when it finishes (it directly calls the operation
2096 modest_mail_operation_notify_end (ModestMailOperation *self)
2098 ModestMailOperationState *state;
2100 /* Notify the observers about the mail opertation end */
2101 state = modest_mail_operation_clone_state (self);
2102 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2103 g_slice_free (ModestMailOperationState, state);