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-simple-list.h>
38 #include <tny-send-queue.h>
39 #include <tny-status.h>
40 #include <tny-folder-observer.h>
41 #include <camel/camel-stream-mem.h>
42 #include <glib/gi18n.h>
43 #include "modest-platform.h"
44 #include <modest-tny-account.h>
45 #include <modest-tny-send-queue.h>
46 #include <modest-runtime.h>
47 #include "modest-text-utils.h"
48 #include "modest-tny-msg.h"
49 #include "modest-tny-folder.h"
50 #include "modest-tny-platform-factory.h"
51 #include "modest-marshal.h"
52 #include "modest-error.h"
53 #include "modest-mail-operation.h"
57 /* 'private'/'protected' functions */
58 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
59 static void modest_mail_operation_init (ModestMailOperation *obj);
60 static void modest_mail_operation_finalize (GObject *obj);
62 static void get_msg_cb (TnyFolder *folder,
68 static void get_msg_status_cb (GObject *obj,
72 static void modest_mail_operation_notify_end (ModestMailOperation *self);
74 static gboolean did_a_cancel = FALSE;
76 enum _ModestMailOperationSignals
78 PROGRESS_CHANGED_SIGNAL,
83 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
84 struct _ModestMailOperationPrivate {
90 ErrorCheckingUserCallback error_checking;
91 gpointer error_checking_user_data;
92 ModestMailOperationStatus status;
93 ModestMailOperationTypeOperation op_type;
96 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
97 MODEST_TYPE_MAIL_OPERATION, \
98 ModestMailOperationPrivate))
100 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
101 priv->status = new_status;\
104 typedef struct _GetMsgAsyncHelper {
105 ModestMailOperation *mail_op;
106 GetMsgAsyncUserCallback user_callback;
111 typedef struct _XFerMsgAsyncHelper
113 ModestMailOperation *mail_op;
115 TnyFolder *dest_folder;
116 XferMsgsAsynUserCallback user_callback;
118 } XFerMsgAsyncHelper;
121 static GObjectClass *parent_class = NULL;
123 static guint signals[NUM_SIGNALS] = {0};
126 modest_mail_operation_get_type (void)
128 static GType my_type = 0;
130 static const GTypeInfo my_info = {
131 sizeof(ModestMailOperationClass),
132 NULL, /* base init */
133 NULL, /* base finalize */
134 (GClassInitFunc) modest_mail_operation_class_init,
135 NULL, /* class finalize */
136 NULL, /* class data */
137 sizeof(ModestMailOperation),
139 (GInstanceInitFunc) modest_mail_operation_init,
142 my_type = g_type_register_static (G_TYPE_OBJECT,
143 "ModestMailOperation",
150 modest_mail_operation_class_init (ModestMailOperationClass *klass)
152 GObjectClass *gobject_class;
153 gobject_class = (GObjectClass*) klass;
155 parent_class = g_type_class_peek_parent (klass);
156 gobject_class->finalize = modest_mail_operation_finalize;
158 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
161 * ModestMailOperation::progress-changed
162 * @self: the #MailOperation that emits the signal
163 * @user_data: user data set when the signal handler was connected
165 * Emitted when the progress of a mail operation changes
167 signals[PROGRESS_CHANGED_SIGNAL] =
168 g_signal_new ("progress-changed",
169 G_TYPE_FROM_CLASS (gobject_class),
171 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
173 g_cclosure_marshal_VOID__POINTER,
174 G_TYPE_NONE, 1, G_TYPE_POINTER);
179 modest_mail_operation_init (ModestMailOperation *obj)
181 ModestMailOperationPrivate *priv;
183 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
185 priv->account = NULL;
186 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
187 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
192 priv->error_checking = NULL;
193 priv->error_checking_user_data = NULL;
197 modest_mail_operation_finalize (GObject *obj)
199 ModestMailOperationPrivate *priv;
201 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
204 g_error_free (priv->error);
208 g_object_unref (priv->source);
212 g_object_unref (priv->account);
213 priv->account = NULL;
217 G_OBJECT_CLASS(parent_class)->finalize (obj);
221 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
224 ModestMailOperation *obj;
225 ModestMailOperationPrivate *priv;
227 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
228 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
230 priv->op_type = op_type;
232 priv->source = g_object_ref(source);
238 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
240 ErrorCheckingUserCallback error_handler,
243 ModestMailOperation *obj;
244 ModestMailOperationPrivate *priv;
246 obj = modest_mail_operation_new (op_type, source);
247 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
249 g_return_val_if_fail (error_handler != NULL, obj);
250 priv->error_checking = error_handler;
256 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
258 ModestMailOperationPrivate *priv;
260 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
261 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
263 if (priv->error_checking != NULL)
264 priv->error_checking (self, priv->error_checking_user_data);
268 ModestMailOperationTypeOperation
269 modest_mail_operation_get_type_operation (ModestMailOperation *self)
271 ModestMailOperationPrivate *priv;
273 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
275 return priv->op_type;
279 modest_mail_operation_is_mine (ModestMailOperation *self,
282 ModestMailOperationPrivate *priv;
284 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
285 if (priv->source == NULL) return FALSE;
287 return priv->source == me;
291 modest_mail_operation_get_source (ModestMailOperation *self)
293 ModestMailOperationPrivate *priv;
295 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
297 return g_object_ref (priv->source);
300 ModestMailOperationStatus
301 modest_mail_operation_get_status (ModestMailOperation *self)
303 ModestMailOperationPrivate *priv;
305 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
306 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
307 MODEST_MAIL_OPERATION_STATUS_INVALID);
309 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
314 modest_mail_operation_get_error (ModestMailOperation *self)
316 ModestMailOperationPrivate *priv;
318 g_return_val_if_fail (self, NULL);
319 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
321 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
326 modest_mail_operation_cancel (ModestMailOperation *self)
328 ModestMailOperationPrivate *priv;
330 if (!MODEST_IS_MAIL_OPERATION (self)) {
331 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
335 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
337 /* cancel current operation in account */
338 tny_account_cancel (priv->account);
343 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
345 /* Notify about operation end */
346 modest_mail_operation_notify_end (self);
352 modest_mail_operation_get_task_done (ModestMailOperation *self)
354 ModestMailOperationPrivate *priv;
356 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
358 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
363 modest_mail_operation_get_task_total (ModestMailOperation *self)
365 ModestMailOperationPrivate *priv;
367 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
369 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
374 modest_mail_operation_is_finished (ModestMailOperation *self)
376 ModestMailOperationPrivate *priv;
377 gboolean retval = FALSE;
379 if (!MODEST_IS_MAIL_OPERATION (self)) {
380 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
384 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
386 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
387 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
388 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
389 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
399 modest_mail_operation_get_id (ModestMailOperation *self)
401 ModestMailOperationPrivate *priv;
403 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
405 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
410 modest_mail_operation_set_id (ModestMailOperation *self,
413 ModestMailOperationPrivate *priv;
415 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
417 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
422 * Creates an image of the current state of a mail operation, the
423 * caller must free it
425 static ModestMailOperationState *
426 modest_mail_operation_clone_state (ModestMailOperation *self)
428 ModestMailOperationState *state;
429 ModestMailOperationPrivate *priv;
431 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
433 state = g_slice_new (ModestMailOperationState);
435 state->status = priv->status;
436 state->op_type = priv->op_type;
437 state->done = priv->done;
438 state->total = priv->total;
439 state->finished = modest_mail_operation_is_finished (self);
444 /* ******************************************************************* */
445 /* ************************** SEND ACTIONS ************************* */
446 /* ******************************************************************* */
449 modest_mail_operation_send_mail (ModestMailOperation *self,
450 TnyTransportAccount *transport_account,
453 TnySendQueue *send_queue = NULL;
454 ModestMailOperationPrivate *priv;
456 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
457 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
458 g_return_if_fail (TNY_IS_MSG (msg));
460 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
462 /* Get account and set it into mail_operation */
463 priv->account = g_object_ref (transport_account);
465 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
466 if (!TNY_IS_SEND_QUEUE(send_queue)) {
467 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
468 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
469 "modest: could not find send queue for account\n");
471 tny_send_queue_add (send_queue, msg, &(priv->error));
474 /* Notify about operation end */
475 modest_mail_operation_notify_end (self);
479 modest_mail_operation_send_new_mail (ModestMailOperation *self,
480 TnyTransportAccount *transport_account,
482 const gchar *from, const gchar *to,
483 const gchar *cc, const gchar *bcc,
484 const gchar *subject, const gchar *plain_body,
485 const gchar *html_body,
486 const GList *attachments_list,
487 TnyHeaderFlags priority_flags)
489 TnyMsg *new_msg = NULL;
490 TnyFolder *folder = NULL;
491 ModestMailOperationPrivate *priv = NULL;
493 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
494 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
496 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
498 /* Get account and set it into mail_operation */
499 priv->account = g_object_ref (transport_account);
501 /* Check parametters */
503 /* Set status failed and set an error */
504 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
505 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
506 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
507 _("Error trying to send a mail. You need to set at least one recipient"));
511 if (html_body == NULL) {
512 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
514 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
517 g_printerr ("modest: failed to create a new msg\n");
521 /* TODO: add priority handling. It's received in the priority_flags operator, and
522 it should have effect in the sending operation */
524 /* Call mail operation */
525 modest_mail_operation_send_mail (self, transport_account, new_msg);
527 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
529 if (draft_msg != NULL) {
530 TnyHeader *header = tny_msg_get_header (draft_msg);
531 tny_folder_remove_msg (folder, header, NULL);
532 g_object_unref (header);
537 g_object_unref (G_OBJECT (new_msg));
541 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
542 TnyTransportAccount *transport_account,
544 const gchar *from, const gchar *to,
545 const gchar *cc, const gchar *bcc,
546 const gchar *subject, const gchar *plain_body,
547 const gchar *html_body,
548 const GList *attachments_list,
549 TnyHeaderFlags priority_flags)
552 TnyFolder *folder = NULL;
553 ModestMailOperationPrivate *priv = NULL;
555 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
556 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
558 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
560 /* Get account and set it into mail_operation */
561 priv->account = g_object_ref (transport_account);
563 if (html_body == NULL) {
564 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
566 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
569 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
570 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
571 "modest: failed to create a new msg\n");
575 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
577 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
578 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
579 "modest: failed to create a new msg\n");
583 if (draft_msg != NULL) {
584 TnyHeader *header = tny_msg_get_header (draft_msg);
585 tny_folder_remove_msg (folder, header, NULL);
586 g_object_unref (header);
589 tny_folder_add_msg (folder, msg, &(priv->error));
595 g_object_unref (G_OBJECT(msg));
597 g_object_unref (G_OBJECT(folder));
599 modest_mail_operation_notify_end (self);
604 ModestMailOperation *mail_op;
605 TnyStoreAccount *account;
606 TnyTransportAccount *transport_account;
609 gchar *retrieve_type;
612 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
613 /* We use this folder observer to track the headers that have been
614 * added to a folder */
617 TnyList *new_headers;
618 } InternalFolderObserver;
622 } InternalFolderObserverClass;
624 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
626 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
627 internal_folder_observer,
629 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
633 foreach_add_item (gpointer header, gpointer user_data)
635 /* printf("DEBUG: %s: header subject=%s\n",
636 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
638 tny_list_prepend (TNY_LIST (user_data),
639 g_object_ref (G_OBJECT (header)));
642 /* This is the method that looks for new messages in a folder */
644 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
646 InternalFolderObserver *derived = (InternalFolderObserver *)self;
648 TnyFolderChangeChanged changed;
650 changed = tny_folder_change_get_changed (change);
652 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
655 /* Get added headers */
656 list = tny_simple_list_new ();
657 tny_folder_change_get_added_headers (change, list);
659 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
660 * __FUNCTION__, tny_list_get_length(list));
663 /* Add them to the folder observer */
664 tny_list_foreach (list, foreach_add_item,
665 derived->new_headers);
667 g_object_unref (G_OBJECT (list));
672 internal_folder_observer_init (InternalFolderObserver *self)
674 self->new_headers = tny_simple_list_new ();
677 internal_folder_observer_finalize (GObject *object)
679 InternalFolderObserver *self;
681 self = (InternalFolderObserver *) object;
682 g_object_unref (self->new_headers);
684 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
687 tny_folder_observer_init (TnyFolderObserverIface *iface)
689 iface->update_func = internal_folder_observer_update;
692 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
694 GObjectClass *object_class;
696 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
697 object_class = (GObjectClass*) klass;
698 object_class->finalize = internal_folder_observer_finalize;
704 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
707 TnyList *folders = tny_simple_list_new ();
709 tny_folder_store_get_folders (store, folders, query, NULL);
710 iter = tny_list_create_iterator (folders);
712 while (!tny_iterator_is_done (iter)) {
714 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
716 tny_list_prepend (all_folders, G_OBJECT (folder));
717 recurse_folders (folder, query, all_folders);
718 g_object_unref (G_OBJECT (folder));
720 tny_iterator_next (iter);
722 g_object_unref (G_OBJECT (iter));
723 g_object_unref (G_OBJECT (folders));
727 * Issues the "progress-changed" signal. The timer won't be removed,
728 * so you must call g_source_remove to stop the signal emission
731 idle_notify_progress (gpointer data)
733 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
734 ModestMailOperationState *state;
736 state = modest_mail_operation_clone_state (mail_op);
737 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
738 g_slice_free (ModestMailOperationState, state);
744 * Issues the "progress-changed" signal and removes the timer. It uses
745 * a lock to ensure that the progress information of the mail
746 * operation is not modified while there are notifications pending
749 idle_notify_progress_once (gpointer data)
753 pair = (ModestPair *) data;
755 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
757 /* Free the state and the reference to the mail operation */
758 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
759 g_object_unref (pair->first);
765 * Used by update_account_thread to notify the queue from the main
766 * loop. We call it inside an idle call to achieve that
769 notify_update_account_queue (gpointer data)
771 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
772 ModestMailOperationPrivate *priv = NULL;
774 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
776 modest_mail_operation_notify_end (mail_op);
777 g_object_unref (mail_op);
783 compare_headers_by_date (gconstpointer a,
786 TnyHeader **header1, **header2;
789 header1 = (TnyHeader **) a;
790 header2 = (TnyHeader **) b;
792 sent1 = tny_header_get_date_sent (*header1);
793 sent2 = tny_header_get_date_sent (*header2);
795 /* We want the most recent ones (greater time_t) at the
804 update_account_thread (gpointer thr_user_data)
806 UpdateAccountInfo *info;
807 TnyList *all_folders = NULL;
808 GPtrArray *new_headers;
809 TnyIterator *iter = NULL;
810 TnyFolderStoreQuery *query = NULL;
811 ModestMailOperationPrivate *priv;
812 ModestTnySendQueue *send_queue;
814 info = (UpdateAccountInfo *) thr_user_data;
815 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
817 /* Get account and set it into mail_operation */
818 priv->account = g_object_ref (info->account);
820 /* Get all the folders. We can do it synchronously because
821 we're already running in a different thread than the UI */
822 all_folders = tny_simple_list_new ();
823 query = tny_folder_store_query_new ();
824 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
825 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
830 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
834 iter = tny_list_create_iterator (all_folders);
835 while (!tny_iterator_is_done (iter)) {
836 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
838 recurse_folders (folder, query, all_folders);
839 tny_iterator_next (iter);
841 g_object_unref (G_OBJECT (iter));
843 /* Update status and notify. We need to call the notification
844 with a source function in order to call it from the main
845 loop. We need that in order not to get into trouble with
846 Gtk+. We use a timeout in order to provide more status
847 information, because the sync tinymail call does not
848 provide it for the moment */
849 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
851 /* Refresh folders */
852 new_headers = g_ptr_array_new ();
853 iter = tny_list_create_iterator (all_folders);
855 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
857 InternalFolderObserver *observer;
858 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
860 /* Refresh the folder */
861 /* Our observer receives notification of new emails during folder refreshes,
862 * so we can use observer->new_headers.
863 * TODO: This does not seem to be providing accurate numbers.
864 * Possibly the observer is notified asynchronously.
866 observer = g_object_new (internal_folder_observer_get_type (), NULL);
867 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
869 /* This gets the status information (headers) from the server.
870 * We use the blocking version, because we are already in a separate
873 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
875 /* If the retrieve type is headers only do nothing more */
876 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
877 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
880 iter = tny_list_create_iterator (observer->new_headers);
881 while (!tny_iterator_is_done (iter)) {
882 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
883 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
884 * __FUNCTION__, tny_account_get_id (priv->account),
885 * tny_header_get_subject (header));
888 /* Apply per-message size limits */
889 if (tny_header_get_message_size (header) < info->max_size)
890 g_ptr_array_add (new_headers, g_object_ref (header));
892 g_object_unref (header);
893 tny_iterator_next (iter);
895 g_object_unref (iter);
898 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
899 g_object_unref (observer);
903 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
905 g_object_unref (G_OBJECT (folder));
906 tny_iterator_next (iter);
909 did_a_cancel = FALSE;
911 g_object_unref (G_OBJECT (iter));
912 g_source_remove (timeout);
914 if (new_headers->len > 0) {
918 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
920 /* Apply message count limit */
921 /* If the number of messages exceeds the maximum, ask the
922 * user to download them all,
923 * as per the UI spec "Retrieval Limits" section in 4.4:
925 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
926 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
927 if (new_headers->len > info->retrieve_limit) {
928 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
929 * with 'Get all' and 'Newest only' buttons. */
930 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
931 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
932 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
933 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
934 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
939 priv->total = MIN (new_headers->len, info->retrieve_limit);
940 while (msg_num < priv->total) {
942 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
943 TnyFolder *folder = tny_header_get_folder (header);
944 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
945 ModestMailOperationState *state;
949 /* We can not just use the mail operation because the
950 values of done and total could change before the
952 state = modest_mail_operation_clone_state (info->mail_op);
953 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
954 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
955 pair, (GDestroyNotify) modest_pair_free);
957 g_object_unref (msg);
958 g_object_unref (folder);
962 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
963 g_ptr_array_free (new_headers, FALSE);
967 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
970 if (priv->account != NULL)
971 g_object_unref (priv->account);
972 priv->account = g_object_ref (info->transport_account);
974 send_queue = modest_runtime_get_send_queue (info->transport_account);
976 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
977 modest_tny_send_queue_try_to_send (send_queue);
978 g_source_remove (timeout);
980 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
981 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
982 "cannot create a send queue for %s\n",
983 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
984 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
987 /* Check if the operation was a success */
989 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
991 /* Update the last updated key */
992 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
993 tny_account_get_id (TNY_ACCOUNT (info->account)),
994 MODEST_ACCOUNT_LAST_UPDATED,
1000 /* Notify about operation end. Note that the info could be
1001 freed before this idle happens, but the mail operation will
1003 g_idle_add (notify_update_account_queue, info->mail_op);
1006 g_object_unref (query);
1007 g_object_unref (all_folders);
1008 g_object_unref (info->account);
1009 g_object_unref (info->transport_account);
1010 g_free (info->retrieve_type);
1011 g_slice_free (UpdateAccountInfo, info);
1017 modest_mail_operation_update_account (ModestMailOperation *self,
1018 const gchar *account_name)
1021 UpdateAccountInfo *info;
1022 ModestMailOperationPrivate *priv;
1023 ModestAccountMgr *mgr;
1024 TnyStoreAccount *modest_account;
1025 TnyTransportAccount *transport_account;
1027 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1028 g_return_val_if_fail (account_name, FALSE);
1030 /* Make sure that we have a connection, and request one
1032 * TODO: Is there some way to trigger this for every attempt to
1033 * use the network? */
1034 if (!modest_platform_connect_and_wait(NULL))
1037 /* Init mail operation. Set total and done to 0, and do not
1038 update them, this way the progress objects will know that
1039 we have no clue about the number of the objects */
1040 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1043 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1045 /* Get the Modest account */
1046 modest_account = (TnyStoreAccount *)
1047 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
1049 TNY_ACCOUNT_TYPE_STORE);
1051 if (!modest_account) {
1052 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1053 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1054 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1055 "cannot get tny store account for %s\n", account_name);
1056 modest_mail_operation_notify_end (self);
1061 /* Get the transport account, we can not do it in the thread
1062 due to some problems with dbus */
1063 transport_account = (TnyTransportAccount *)
1064 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1066 if (!transport_account) {
1067 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1068 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1069 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1070 "cannot get tny transport account for %s\n", account_name);
1071 modest_mail_operation_notify_end (self);
1076 /* Create the helper object */
1077 info = g_slice_new (UpdateAccountInfo);
1078 info->mail_op = self;
1079 info->account = modest_account;
1080 info->transport_account = transport_account;
1082 /* Get the message size limit */
1083 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1084 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1085 if (info->max_size == 0)
1086 info->max_size = G_MAXINT;
1088 info->max_size = info->max_size * KB;
1090 /* Get per-account retrieval type */
1091 mgr = modest_runtime_get_account_mgr ();
1092 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1093 MODEST_ACCOUNT_RETRIEVE, FALSE);
1095 /* Get per-account message amount retrieval limit */
1096 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1097 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1098 if (info->retrieve_limit == 0)
1099 info->retrieve_limit = G_MAXINT;
1101 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1103 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1108 /* ******************************************************************* */
1109 /* ************************** STORE ACTIONS ************************* */
1110 /* ******************************************************************* */
1114 modest_mail_operation_create_folder (ModestMailOperation *self,
1115 TnyFolderStore *parent,
1118 ModestMailOperationPrivate *priv;
1119 TnyFolder *new_folder = NULL;
1121 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1122 g_return_val_if_fail (name, NULL);
1124 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1127 if (TNY_IS_FOLDER (parent)) {
1128 /* Check folder rules */
1129 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1130 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1131 /* Set status failed and set an error */
1132 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1133 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1134 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1135 _("mail_in_ui_folder_create_error"));
1140 /* Create the folder */
1141 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1142 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1144 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1147 /* Notify about operation end */
1148 modest_mail_operation_notify_end (self);
1154 modest_mail_operation_remove_folder (ModestMailOperation *self,
1156 gboolean remove_to_trash)
1158 TnyAccount *account;
1159 ModestMailOperationPrivate *priv;
1160 ModestTnyFolderRules rules;
1162 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1163 g_return_if_fail (TNY_IS_FOLDER (folder));
1165 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1167 /* Check folder rules */
1168 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1169 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1170 /* Set status failed and set an error */
1171 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1172 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1173 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1174 _("mail_in_ui_folder_delete_error"));
1178 /* Get the account */
1179 account = modest_tny_folder_get_account (folder);
1180 priv->account = g_object_ref(account);
1182 /* Delete folder or move to trash */
1183 if (remove_to_trash) {
1184 TnyFolder *trash_folder = NULL;
1185 trash_folder = modest_tny_account_get_special_folder (account,
1186 TNY_FOLDER_TYPE_TRASH);
1187 /* TODO: error_handling */
1188 modest_mail_operation_xfer_folder (self, folder,
1189 TNY_FOLDER_STORE (trash_folder), TRUE);
1191 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1193 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1194 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1197 g_object_unref (G_OBJECT (parent));
1199 g_object_unref (G_OBJECT (account));
1202 /* Notify about operation end */
1203 modest_mail_operation_notify_end (self);
1207 transfer_folder_status_cb (GObject *obj,
1211 ModestMailOperation *self;
1212 ModestMailOperationPrivate *priv;
1213 ModestMailOperationState *state;
1215 g_return_if_fail (status != NULL);
1216 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1218 self = MODEST_MAIL_OPERATION (user_data);
1219 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1221 if ((status->position == 1) && (status->of_total == 100))
1224 priv->done = status->position;
1225 priv->total = status->of_total;
1227 state = modest_mail_operation_clone_state (self);
1228 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1229 g_slice_free (ModestMailOperationState, state);
1234 transfer_folder_cb (TnyFolder *folder,
1235 TnyFolderStore *into,
1237 TnyFolder *new_folder, GError **err,
1240 ModestMailOperation *self = NULL;
1241 ModestMailOperationPrivate *priv = NULL;
1243 self = MODEST_MAIL_OPERATION (user_data);
1245 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1248 priv->error = g_error_copy (*err);
1250 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1251 } else if (cancelled) {
1252 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1253 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1254 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1255 _("Transference of %s was cancelled."),
1256 tny_folder_get_name (folder));
1259 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1263 g_object_unref (folder);
1264 g_object_unref (into);
1265 if (new_folder != NULL)
1266 g_object_unref (new_folder);
1268 /* Notify about operation end */
1269 modest_mail_operation_notify_end (self);
1273 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1275 TnyFolderStore *parent,
1276 gboolean delete_original)
1278 ModestMailOperationPrivate *priv = NULL;
1279 ModestTnyFolderRules parent_rules, rules;
1281 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1282 g_return_if_fail (TNY_IS_FOLDER (folder));
1283 g_return_if_fail (TNY_IS_FOLDER (parent));
1285 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1287 /* Get account and set it into mail_operation */
1288 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1289 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1291 /* Get folder rules */
1292 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1293 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1295 if (!TNY_IS_FOLDER_STORE (parent)) {
1299 /* The moveable restriction is applied also to copy operation */
1300 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1301 /* Set status failed and set an error */
1302 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1303 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1304 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1305 _("mail_in_ui_folder_move_target_error"));
1307 /* Notify the queue */
1308 modest_mail_operation_notify_end (self);
1309 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1310 /* Set status failed and set an error */
1311 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1312 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1313 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1314 _("FIXME: parent folder does not accept new folders"));
1316 /* Notify the queue */
1317 modest_mail_operation_notify_end (self);
1319 /* Pick references for async calls */
1320 g_object_ref (folder);
1321 g_object_ref (parent);
1323 /* Move/Copy folder */
1324 tny_folder_copy_async (folder,
1326 tny_folder_get_name (folder),
1329 transfer_folder_status_cb,
1335 modest_mail_operation_rename_folder (ModestMailOperation *self,
1339 ModestMailOperationPrivate *priv;
1340 ModestTnyFolderRules rules;
1342 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1343 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1344 g_return_if_fail (name);
1346 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1348 /* Get account and set it into mail_operation */
1349 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1351 /* Check folder rules */
1352 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1353 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1354 /* Set status failed and set an error */
1355 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1356 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1357 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1358 _("FIXME: unable to rename"));
1360 /* Notify about operation end */
1361 modest_mail_operation_notify_end (self);
1363 /* Rename. Camel handles folder subscription/unsubscription */
1364 TnyFolderStore *into;
1366 into = tny_folder_get_folder_store (folder);
1367 tny_folder_copy_async (folder, into, name, TRUE,
1369 transfer_folder_status_cb,
1372 g_object_unref (into);
1377 /* ******************************************************************* */
1378 /* ************************** MSG ACTIONS ************************* */
1379 /* ******************************************************************* */
1381 void modest_mail_operation_get_msg (ModestMailOperation *self,
1383 GetMsgAsyncUserCallback user_callback,
1386 GetMsgAsyncHelper *helper = NULL;
1388 ModestMailOperationPrivate *priv;
1390 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1391 g_return_if_fail (TNY_IS_HEADER (header));
1393 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1394 folder = tny_header_get_folder (header);
1396 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1398 /* Get message from folder */
1400 /* Get account and set it into mail_operation */
1401 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1403 helper = g_slice_new0 (GetMsgAsyncHelper);
1404 helper->mail_op = self;
1405 helper->user_callback = user_callback;
1406 helper->pending_ops = 1;
1407 helper->user_data = user_data;
1409 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1411 g_object_unref (G_OBJECT (folder));
1413 /* Set status failed and set an error */
1414 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1415 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1416 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1417 _("Error trying to get a message. No folder found for header"));
1419 /* Notify the queue */
1420 modest_mail_operation_notify_end (self);
1425 get_msg_cb (TnyFolder *folder,
1431 GetMsgAsyncHelper *helper = NULL;
1432 ModestMailOperation *self = NULL;
1433 ModestMailOperationPrivate *priv = NULL;
1435 helper = (GetMsgAsyncHelper *) user_data;
1436 g_return_if_fail (helper != NULL);
1437 self = helper->mail_op;
1438 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1439 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1441 helper->pending_ops--;
1443 /* Check errors and cancel */
1445 priv->error = g_error_copy (*error);
1446 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1450 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1451 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1452 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1453 _("Error trying to refresh the contents of %s"),
1454 tny_folder_get_name (folder));
1458 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1460 /* If user defined callback function was defined, call it */
1461 if (helper->user_callback) {
1462 helper->user_callback (self, NULL, msg, helper->user_data);
1467 if (helper->pending_ops == 0) {
1468 g_slice_free (GetMsgAsyncHelper, helper);
1470 /* Notify about operation end */
1471 modest_mail_operation_notify_end (self);
1476 get_msg_status_cb (GObject *obj,
1480 GetMsgAsyncHelper *helper = NULL;
1481 ModestMailOperation *self;
1482 ModestMailOperationPrivate *priv;
1483 ModestMailOperationState *state;
1485 g_return_if_fail (status != NULL);
1486 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1488 helper = (GetMsgAsyncHelper *) user_data;
1489 g_return_if_fail (helper != NULL);
1491 self = helper->mail_op;
1492 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1494 if ((status->position == 1) && (status->of_total == 100))
1500 state = modest_mail_operation_clone_state (self);
1501 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1502 g_slice_free (ModestMailOperationState, state);
1505 /****************************************************/
1507 ModestMailOperation *mail_op;
1509 GetMsgAsyncUserCallback user_callback;
1511 GDestroyNotify notify;
1515 GetMsgAsyncUserCallback user_callback;
1519 ModestMailOperation *mail_op;
1520 } NotifyGetMsgsInfo;
1524 * Used by get_msgs_full_thread to call the user_callback for each
1525 * message that has been read
1528 notify_get_msgs_full (gpointer data)
1530 NotifyGetMsgsInfo *info;
1532 info = (NotifyGetMsgsInfo *) data;
1534 /* Call the user callback */
1535 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1537 g_slice_free (NotifyGetMsgsInfo, info);
1543 * Used by get_msgs_full_thread to free al the thread resources and to
1544 * call the destroy function for the passed user_data
1547 get_msgs_full_destroyer (gpointer data)
1549 GetFullMsgsInfo *info;
1551 info = (GetFullMsgsInfo *) data;
1554 info->notify (info->user_data);
1557 g_object_unref (info->headers);
1558 g_slice_free (GetFullMsgsInfo, info);
1564 get_msgs_full_thread (gpointer thr_user_data)
1566 GetFullMsgsInfo *info;
1567 ModestMailOperationPrivate *priv = NULL;
1568 TnyIterator *iter = NULL;
1570 info = (GetFullMsgsInfo *) thr_user_data;
1571 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1573 iter = tny_list_create_iterator (info->headers);
1574 while (!tny_iterator_is_done (iter)) {
1578 header = TNY_HEADER (tny_iterator_get_current (iter));
1579 folder = tny_header_get_folder (header);
1581 /* Get message from folder */
1584 /* The callback will call it per each header */
1585 msg = tny_folder_get_msg (folder, header, &(priv->error));
1588 ModestMailOperationState *state;
1593 /* notify progress */
1594 state = modest_mail_operation_clone_state (info->mail_op);
1595 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1596 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1597 pair, (GDestroyNotify) modest_pair_free);
1599 /* The callback is the responsible for
1600 freeing the message */
1601 if (info->user_callback) {
1602 NotifyGetMsgsInfo *info_notify;
1603 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1604 info_notify->user_callback = info->user_callback;
1605 info_notify->mail_op = info->mail_op;
1606 info_notify->header = g_object_ref (header);
1607 info_notify->msg = g_object_ref (msg);
1608 info_notify->user_data = info->user_data;
1609 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1610 notify_get_msgs_full,
1613 g_object_unref (msg);
1616 /* Set status failed and set an error */
1617 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1618 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1619 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1620 "Error trying to get a message. No folder found for header");
1622 g_object_unref (header);
1623 tny_iterator_next (iter);
1626 /* Set operation status */
1627 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1628 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1630 /* Notify about operation end */
1631 g_idle_add (notify_update_account_queue, info->mail_op);
1633 /* Free thread resources. Will be called after all previous idles */
1634 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1640 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1641 TnyList *header_list,
1642 GetMsgAsyncUserCallback user_callback,
1644 GDestroyNotify notify)
1646 TnyHeader *header = NULL;
1647 TnyFolder *folder = NULL;
1649 ModestMailOperationPrivate *priv = NULL;
1650 GetFullMsgsInfo *info = NULL;
1651 gboolean size_ok = TRUE;
1653 TnyIterator *iter = NULL;
1655 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1657 /* Init mail operation */
1658 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1659 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1661 priv->total = tny_list_get_length(header_list);
1663 /* Get account and set it into mail_operation */
1664 if (tny_list_get_length (header_list) >= 1) {
1665 iter = tny_list_create_iterator (header_list);
1666 header = TNY_HEADER (tny_iterator_get_current (iter));
1667 folder = tny_header_get_folder (header);
1668 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1669 g_object_unref (header);
1670 g_object_unref (folder);
1672 if (tny_list_get_length (header_list) == 1) {
1673 g_object_unref (iter);
1678 /* Get msg size limit */
1679 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1680 MODEST_CONF_MSG_SIZE_LIMIT,
1683 g_clear_error (&(priv->error));
1684 max_size = G_MAXINT;
1686 max_size = max_size * KB;
1689 /* Check message size limits. If there is only one message
1690 always retrieve it */
1692 while (!tny_iterator_is_done (iter) && size_ok) {
1693 header = TNY_HEADER (tny_iterator_get_current (iter));
1694 if (tny_header_get_message_size (header) >= max_size)
1696 g_object_unref (header);
1697 tny_iterator_next (iter);
1699 g_object_unref (iter);
1703 /* Create the info */
1704 info = g_slice_new0 (GetFullMsgsInfo);
1705 info->mail_op = self;
1706 info->user_callback = user_callback;
1707 info->user_data = user_data;
1708 info->headers = g_object_ref (header_list);
1709 info->notify = notify;
1711 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1713 /* Set status failed and set an error */
1714 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1715 /* FIXME: the error msg is different for pop */
1716 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1717 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1718 _("emev_ni_ui_imap_msg_size_exceed_error"));
1719 /* Remove from queue and free resources */
1720 modest_mail_operation_notify_end (self);
1728 modest_mail_operation_remove_msg (ModestMailOperation *self,
1730 gboolean remove_to_trash)
1733 ModestMailOperationPrivate *priv;
1735 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1736 g_return_if_fail (TNY_IS_HEADER (header));
1738 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1739 folder = tny_header_get_folder (header);
1741 /* Get account and set it into mail_operation */
1742 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1744 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1746 /* Delete or move to trash */
1747 if (remove_to_trash) {
1748 TnyFolder *trash_folder;
1749 TnyStoreAccount *store_account;
1751 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1752 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1753 TNY_FOLDER_TYPE_TRASH);
1758 headers = tny_simple_list_new ();
1759 tny_list_append (headers, G_OBJECT (header));
1760 g_object_unref (header);
1763 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1764 g_object_unref (headers);
1765 /* g_object_unref (trash_folder); */
1767 ModestMailOperationPrivate *priv;
1769 /* Set status failed and set an error */
1770 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1771 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1772 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1773 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1774 _("Error trying to delete a message. Trash folder not found"));
1777 g_object_unref (G_OBJECT (store_account));
1779 tny_folder_remove_msg (folder, header, &(priv->error));
1781 tny_folder_sync(folder, TRUE, &(priv->error));
1786 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1788 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1791 g_object_unref (G_OBJECT (folder));
1793 /* Notify about operation end */
1794 modest_mail_operation_notify_end (self);
1798 transfer_msgs_status_cb (GObject *obj,
1802 XFerMsgAsyncHelper *helper = NULL;
1803 ModestMailOperation *self;
1804 ModestMailOperationPrivate *priv;
1805 ModestMailOperationState *state;
1808 g_return_if_fail (status != NULL);
1809 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1811 helper = (XFerMsgAsyncHelper *) user_data;
1812 g_return_if_fail (helper != NULL);
1814 self = helper->mail_op;
1815 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1817 if ((status->position == 1) && (status->of_total == 100))
1820 priv->done = status->position;
1821 priv->total = status->of_total;
1823 state = modest_mail_operation_clone_state (self);
1824 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1825 g_slice_free (ModestMailOperationState, state);
1830 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1832 XFerMsgAsyncHelper *helper;
1833 ModestMailOperation *self;
1834 ModestMailOperationPrivate *priv;
1836 helper = (XFerMsgAsyncHelper *) user_data;
1837 self = helper->mail_op;
1839 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1842 priv->error = g_error_copy (*err);
1844 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1845 } else if (cancelled) {
1846 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1847 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1848 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1849 _("Error trying to refresh the contents of %s"),
1850 tny_folder_get_name (folder));
1853 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1856 /* If user defined callback function was defined, call it */
1857 if (helper->user_callback) {
1858 helper->user_callback (priv->source, helper->user_data);
1862 g_object_unref (helper->headers);
1863 g_object_unref (helper->dest_folder);
1864 g_object_unref (helper->mail_op);
1865 g_slice_free (XFerMsgAsyncHelper, helper);
1866 g_object_unref (folder);
1868 /* Notify about operation end */
1869 modest_mail_operation_notify_end (self);
1873 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1876 gboolean delete_original,
1877 XferMsgsAsynUserCallback user_callback,
1880 ModestMailOperationPrivate *priv;
1882 TnyFolder *src_folder;
1883 XFerMsgAsyncHelper *helper;
1885 ModestTnyFolderRules rules;
1887 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1888 g_return_if_fail (TNY_IS_LIST (headers));
1889 g_return_if_fail (TNY_IS_FOLDER (folder));
1891 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1894 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1896 /* Apply folder rules */
1897 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1899 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1900 /* Set status failed and set an error */
1901 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1902 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1903 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1904 _("FIXME: folder does not accept msgs"));
1905 /* Notify the queue */
1906 modest_mail_operation_notify_end (self);
1910 /* Create the helper */
1911 helper = g_slice_new0 (XFerMsgAsyncHelper);
1912 helper->mail_op = g_object_ref(self);
1913 helper->dest_folder = g_object_ref(folder);
1914 helper->headers = g_object_ref(headers);
1915 helper->user_callback = user_callback;
1916 helper->user_data = user_data;
1918 /* Get source folder */
1919 iter = tny_list_create_iterator (headers);
1920 header = TNY_HEADER (tny_iterator_get_current (iter));
1921 src_folder = tny_header_get_folder (header);
1922 g_object_unref (header);
1923 g_object_unref (iter);
1925 /* Get account and set it into mail_operation */
1926 priv->account = modest_tny_folder_get_account (src_folder);
1928 /* Transfer messages */
1929 tny_folder_transfer_msgs_async (src_folder,
1934 transfer_msgs_status_cb,
1940 on_refresh_folder (TnyFolder *folder,
1945 ModestMailOperation *self;
1946 ModestMailOperationPrivate *priv;
1948 self = MODEST_MAIL_OPERATION (user_data);
1949 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1952 priv->error = g_error_copy (*error);
1953 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1958 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1959 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1960 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1961 _("Error trying to refresh the contents of %s"),
1962 tny_folder_get_name (folder));
1966 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1970 g_object_unref (folder);
1972 /* Notify about operation end */
1973 modest_mail_operation_notify_end (self);
1977 on_refresh_folder_status_update (GObject *obj,
1981 ModestMailOperation *self;
1982 ModestMailOperationPrivate *priv;
1983 ModestMailOperationState *state;
1985 g_return_if_fail (status != NULL);
1986 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1988 self = MODEST_MAIL_OPERATION (user_data);
1989 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1991 priv->done = status->position;
1992 priv->total = status->of_total;
1994 state = modest_mail_operation_clone_state (self);
1995 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1996 g_slice_free (ModestMailOperationState, state);
2000 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2003 ModestMailOperationPrivate *priv;
2005 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2007 /* Pick a reference */
2008 g_object_ref (folder);
2010 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2012 /* Get account and set it into mail_operation */
2013 priv->account = modest_tny_folder_get_account (folder);
2015 /* Refresh the folder. TODO: tinymail could issue a status
2016 updates before the callback call then this could happen. We
2017 must review the design */
2018 tny_folder_refresh_async (folder,
2020 on_refresh_folder_status_update,
2026 * It's used by the mail operation queue to notify the observers
2027 * attached to that signal that the operation finished. We need to use
2028 * that because tinymail does not give us the progress of a given
2029 * operation when it finishes (it directly calls the operation
2033 modest_mail_operation_notify_end (ModestMailOperation *self)
2035 ModestMailOperationState *state;
2037 /* Notify the observers about the mail opertation end */
2038 state = modest_mail_operation_clone_state (self);
2039 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2040 g_slice_free (ModestMailOperationState, state);