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 tny_header_set_flags (header, priority_flags);
533 /* Call mail operation */
534 modest_mail_operation_send_mail (self, transport_account, new_msg);
536 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
538 if (draft_msg != NULL) {
539 header = tny_msg_get_header (draft_msg);
540 /* Note: This can fail (with a warning) if the message is not really already in a folder,
541 * because this function requires it to have a UID. */
542 tny_folder_remove_msg (folder, header, NULL);
543 g_object_unref (header);
548 g_object_unref (G_OBJECT (new_msg));
552 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
553 TnyTransportAccount *transport_account,
555 const gchar *from, const gchar *to,
556 const gchar *cc, const gchar *bcc,
557 const gchar *subject, const gchar *plain_body,
558 const gchar *html_body,
559 const GList *attachments_list,
560 TnyHeaderFlags priority_flags)
563 TnyFolder *folder = NULL;
564 TnyHeader *header = NULL;
565 ModestMailOperationPrivate *priv = NULL;
567 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
568 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
570 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
572 /* Get account and set it into mail_operation */
573 priv->account = g_object_ref (transport_account);
575 if (html_body == NULL) {
576 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
578 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
581 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
582 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
583 "modest: failed to create a new msg\n");
587 /* add priority flags */
588 header = tny_msg_get_header (msg);
589 tny_header_set_flags (header, priority_flags);
591 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
593 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
594 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
595 "modest: failed to create a new msg\n");
599 if (draft_msg != NULL) {
600 header = tny_msg_get_header (draft_msg);
601 tny_folder_remove_msg (folder, header, NULL);
602 g_object_unref (header);
605 tny_folder_add_msg (folder, msg, &(priv->error));
611 g_object_unref (G_OBJECT(msg));
613 g_object_unref (G_OBJECT(folder));
615 modest_mail_operation_notify_end (self);
620 ModestMailOperation *mail_op;
621 TnyStoreAccount *account;
622 TnyTransportAccount *transport_account;
625 gchar *retrieve_type;
628 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
629 /* We use this folder observer to track the headers that have been
630 * added to a folder */
633 TnyList *new_headers;
634 } InternalFolderObserver;
638 } InternalFolderObserverClass;
640 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
642 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
643 internal_folder_observer,
645 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
649 foreach_add_item (gpointer header, gpointer user_data)
651 /* printf("DEBUG: %s: header subject=%s\n",
652 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
654 tny_list_prepend (TNY_LIST (user_data),
655 g_object_ref (G_OBJECT (header)));
658 /* This is the method that looks for new messages in a folder */
660 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
662 InternalFolderObserver *derived = (InternalFolderObserver *)self;
664 TnyFolderChangeChanged changed;
666 changed = tny_folder_change_get_changed (change);
668 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
671 /* Get added headers */
672 list = tny_simple_list_new ();
673 tny_folder_change_get_added_headers (change, list);
675 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
676 * __FUNCTION__, tny_list_get_length(list));
679 /* Add them to the folder observer */
680 tny_list_foreach (list, foreach_add_item,
681 derived->new_headers);
683 g_object_unref (G_OBJECT (list));
688 internal_folder_observer_init (InternalFolderObserver *self)
690 self->new_headers = tny_simple_list_new ();
693 internal_folder_observer_finalize (GObject *object)
695 InternalFolderObserver *self;
697 self = (InternalFolderObserver *) object;
698 g_object_unref (self->new_headers);
700 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
703 tny_folder_observer_init (TnyFolderObserverIface *iface)
705 iface->update_func = internal_folder_observer_update;
708 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
710 GObjectClass *object_class;
712 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
713 object_class = (GObjectClass*) klass;
714 object_class->finalize = internal_folder_observer_finalize;
720 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
723 TnyList *folders = tny_simple_list_new ();
725 tny_folder_store_get_folders (store, folders, query, NULL);
726 iter = tny_list_create_iterator (folders);
728 while (!tny_iterator_is_done (iter)) {
730 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
732 tny_list_prepend (all_folders, G_OBJECT (folder));
733 recurse_folders (folder, query, all_folders);
734 g_object_unref (G_OBJECT (folder));
736 tny_iterator_next (iter);
738 g_object_unref (G_OBJECT (iter));
739 g_object_unref (G_OBJECT (folders));
743 * Issues the "progress-changed" signal. The timer won't be removed,
744 * so you must call g_source_remove to stop the signal emission
747 idle_notify_progress (gpointer data)
749 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
750 ModestMailOperationState *state;
752 state = modest_mail_operation_clone_state (mail_op);
753 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
754 g_slice_free (ModestMailOperationState, state);
760 * Issues the "progress-changed" signal and removes the timer. It uses
761 * a lock to ensure that the progress information of the mail
762 * operation is not modified while there are notifications pending
765 idle_notify_progress_once (gpointer data)
769 pair = (ModestPair *) data;
771 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
773 /* Free the state and the reference to the mail operation */
774 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
775 g_object_unref (pair->first);
781 * Used by update_account_thread to notify the queue from the main
782 * loop. We call it inside an idle call to achieve that
785 notify_update_account_queue (gpointer data)
787 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
788 ModestMailOperationPrivate *priv = NULL;
790 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
792 modest_mail_operation_notify_end (mail_op);
793 g_object_unref (mail_op);
799 compare_headers_by_date (gconstpointer a,
802 TnyHeader **header1, **header2;
805 header1 = (TnyHeader **) a;
806 header2 = (TnyHeader **) b;
808 sent1 = tny_header_get_date_sent (*header1);
809 sent2 = tny_header_get_date_sent (*header2);
811 /* We want the most recent ones (greater time_t) at the
820 set_last_updated_idle (gpointer data)
822 /* It does not matter if the time is not exactly the same than
823 the time when this idle was called, it's just an
824 approximation and it won't be very different */
825 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
827 MODEST_ACCOUNT_LAST_UPDATED,
835 update_account_thread (gpointer thr_user_data)
837 UpdateAccountInfo *info;
838 TnyList *all_folders = NULL;
839 GPtrArray *new_headers;
840 TnyIterator *iter = NULL;
841 TnyFolderStoreQuery *query = NULL;
842 ModestMailOperationPrivate *priv;
843 ModestTnySendQueue *send_queue;
846 info = (UpdateAccountInfo *) thr_user_data;
847 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
849 /* Get account and set it into mail_operation */
850 priv->account = g_object_ref (info->account);
853 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
854 * show any updates unless we do that
856 if (TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
857 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
859 /* Get all the folders. We can do it synchronously because
860 we're already running in a different thread than the UI */
861 all_folders = tny_simple_list_new ();
862 query = tny_folder_store_query_new ();
863 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
864 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
869 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
873 iter = tny_list_create_iterator (all_folders);
874 while (!tny_iterator_is_done (iter)) {
875 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
877 recurse_folders (folder, query, all_folders);
878 tny_iterator_next (iter);
880 g_object_unref (G_OBJECT (iter));
882 /* Update status and notify. We need to call the notification
883 with a source function in order to call it from the main
884 loop. We need that in order not to get into trouble with
885 Gtk+. We use a timeout in order to provide more status
886 information, because the sync tinymail call does not
887 provide it for the moment */
888 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
890 /* Refresh folders */
891 new_headers = g_ptr_array_new ();
892 iter = tny_list_create_iterator (all_folders);
894 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
896 InternalFolderObserver *observer;
897 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
899 /* Refresh the folder */
900 /* Our observer receives notification of new emails during folder refreshes,
901 * so we can use observer->new_headers.
902 * TODO: This does not seem to be providing accurate numbers.
903 * Possibly the observer is notified asynchronously.
905 observer = g_object_new (internal_folder_observer_get_type (), NULL);
906 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
908 /* This gets the status information (headers) from the server.
909 * We use the blocking version, because we are already in a separate
913 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
914 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
917 /* If the retrieve type is full messages, refresh and get the messages */
918 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
920 iter = tny_list_create_iterator (observer->new_headers);
921 while (!tny_iterator_is_done (iter)) {
922 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
923 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
924 * __FUNCTION__, tny_account_get_id (priv->account),
925 * tny_header_get_subject (header));
928 /* Apply per-message size limits */
929 if (tny_header_get_message_size (header) < info->max_size)
930 g_ptr_array_add (new_headers, g_object_ref (header));
932 g_object_unref (header);
933 tny_iterator_next (iter);
935 g_object_unref (iter);
938 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
939 g_object_unref (observer);
943 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
945 g_object_unref (G_OBJECT (folder));
946 tny_iterator_next (iter);
949 did_a_cancel = FALSE;
951 g_object_unref (G_OBJECT (iter));
952 g_source_remove (timeout);
954 if (new_headers->len > 0) {
958 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
960 /* Apply message count limit */
961 /* If the number of messages exceeds the maximum, ask the
962 * user to download them all,
963 * as per the UI spec "Retrieval Limits" section in 4.4:
965 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
966 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
967 if (new_headers->len > info->retrieve_limit) {
968 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
969 * with 'Get all' and 'Newest only' buttons. */
970 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
971 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
972 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
973 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
974 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
979 priv->total = MIN (new_headers->len, info->retrieve_limit);
980 while (msg_num < priv->total) {
982 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
983 TnyFolder *folder = tny_header_get_folder (header);
984 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
985 ModestMailOperationState *state;
989 /* We can not just use the mail operation because the
990 values of done and total could change before the
992 state = modest_mail_operation_clone_state (info->mail_op);
993 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
994 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
995 pair, (GDestroyNotify) modest_pair_free);
997 g_object_unref (msg);
998 g_object_unref (folder);
1002 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1003 g_ptr_array_free (new_headers, FALSE);
1007 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1010 if (priv->account != NULL)
1011 g_object_unref (priv->account);
1012 priv->account = g_object_ref (info->transport_account);
1014 send_queue = modest_runtime_get_send_queue (info->transport_account);
1016 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
1017 modest_tny_send_queue_try_to_send (send_queue);
1018 g_source_remove (timeout);
1020 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1021 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1022 "cannot create a send queue for %s\n",
1023 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1024 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1027 /* Check if the operation was a success */
1029 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1031 /* Update the last updated key */
1032 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1033 set_last_updated_idle,
1034 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1035 (GDestroyNotify) g_free);
1039 /* Notify about operation end. Note that the info could be
1040 freed before this idle happens, but the mail operation will
1042 g_idle_add (notify_update_account_queue, info->mail_op);
1045 g_object_unref (query);
1046 g_object_unref (all_folders);
1047 g_object_unref (info->account);
1048 g_object_unref (info->transport_account);
1049 g_free (info->retrieve_type);
1050 g_slice_free (UpdateAccountInfo, info);
1056 modest_mail_operation_update_account (ModestMailOperation *self,
1057 const gchar *account_name)
1060 UpdateAccountInfo *info;
1061 ModestMailOperationPrivate *priv;
1062 ModestAccountMgr *mgr;
1063 TnyStoreAccount *modest_account;
1064 TnyTransportAccount *transport_account;
1066 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1067 g_return_val_if_fail (account_name, FALSE);
1069 /* Make sure that we have a connection, and request one
1071 * TODO: Is there some way to trigger this for every attempt to
1072 * use the network? */
1073 if (!modest_platform_connect_and_wait(NULL))
1076 /* Init mail operation. Set total and done to 0, and do not
1077 update them, this way the progress objects will know that
1078 we have no clue about the number of the objects */
1079 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1082 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1084 /* Get the Modest account */
1085 modest_account = (TnyStoreAccount *)
1086 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1088 TNY_ACCOUNT_TYPE_STORE);
1090 if (!modest_account) {
1091 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1092 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1093 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1094 "cannot get tny store account for %s\n", account_name);
1095 modest_mail_operation_notify_end (self);
1101 /* Get the transport account, we can not do it in the thread
1102 due to some problems with dbus */
1103 transport_account = (TnyTransportAccount *)
1104 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1106 if (!transport_account) {
1107 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1108 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1109 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1110 "cannot get tny transport account for %s\n", account_name);
1111 modest_mail_operation_notify_end (self);
1116 /* Create the helper object */
1117 info = g_slice_new (UpdateAccountInfo);
1118 info->mail_op = self;
1119 info->account = modest_account;
1120 info->transport_account = transport_account;
1122 /* Get the message size limit */
1123 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1124 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1125 if (info->max_size == 0)
1126 info->max_size = G_MAXINT;
1128 info->max_size = info->max_size * KB;
1130 /* Get per-account retrieval type */
1131 mgr = modest_runtime_get_account_mgr ();
1132 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1133 MODEST_ACCOUNT_RETRIEVE, FALSE);
1135 /* Get per-account message amount retrieval limit */
1136 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1137 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1138 if (info->retrieve_limit == 0)
1139 info->retrieve_limit = G_MAXINT;
1141 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1143 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1148 /* ******************************************************************* */
1149 /* ************************** STORE ACTIONS ************************* */
1150 /* ******************************************************************* */
1154 modest_mail_operation_create_folder (ModestMailOperation *self,
1155 TnyFolderStore *parent,
1158 ModestMailOperationPrivate *priv;
1159 TnyFolder *new_folder = NULL;
1161 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1162 g_return_val_if_fail (name, NULL);
1164 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1167 if (TNY_IS_FOLDER (parent)) {
1168 /* Check folder rules */
1169 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1170 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1171 /* Set status failed and set an error */
1172 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1173 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1174 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1175 _("mail_in_ui_folder_create_error"));
1180 /* Create the folder */
1181 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1182 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1184 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1187 /* Notify about operation end */
1188 modest_mail_operation_notify_end (self);
1194 modest_mail_operation_remove_folder (ModestMailOperation *self,
1196 gboolean remove_to_trash)
1198 TnyAccount *account;
1199 ModestMailOperationPrivate *priv;
1200 ModestTnyFolderRules rules;
1202 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1203 g_return_if_fail (TNY_IS_FOLDER (folder));
1205 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1207 /* Check folder rules */
1208 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1209 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1210 /* Set status failed and set an error */
1211 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1212 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1213 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1214 _("mail_in_ui_folder_delete_error"));
1218 /* Get the account */
1219 account = modest_tny_folder_get_account (folder);
1220 priv->account = g_object_ref(account);
1222 /* Delete folder or move to trash */
1223 if (remove_to_trash) {
1224 TnyFolder *trash_folder = NULL;
1225 trash_folder = modest_tny_account_get_special_folder (account,
1226 TNY_FOLDER_TYPE_TRASH);
1227 /* TODO: error_handling */
1228 modest_mail_operation_xfer_folder (self, folder,
1229 TNY_FOLDER_STORE (trash_folder), TRUE);
1231 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1233 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1234 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1237 g_object_unref (G_OBJECT (parent));
1239 g_object_unref (G_OBJECT (account));
1242 /* Notify about operation end */
1243 modest_mail_operation_notify_end (self);
1247 transfer_folder_status_cb (GObject *obj,
1251 ModestMailOperation *self;
1252 ModestMailOperationPrivate *priv;
1253 ModestMailOperationState *state;
1255 g_return_if_fail (status != NULL);
1256 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1258 self = MODEST_MAIL_OPERATION (user_data);
1259 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1261 if ((status->position == 1) && (status->of_total == 100))
1264 priv->done = status->position;
1265 priv->total = status->of_total;
1267 state = modest_mail_operation_clone_state (self);
1268 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1269 g_slice_free (ModestMailOperationState, state);
1274 transfer_folder_cb (TnyFolder *folder,
1275 TnyFolderStore *into,
1277 TnyFolder *new_folder, GError **err,
1280 ModestMailOperation *self = NULL;
1281 ModestMailOperationPrivate *priv = NULL;
1283 self = MODEST_MAIL_OPERATION (user_data);
1285 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1288 priv->error = g_error_copy (*err);
1290 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1291 } else if (cancelled) {
1292 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1293 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1294 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1295 _("Transference of %s was cancelled."),
1296 tny_folder_get_name (folder));
1299 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1303 g_object_unref (folder);
1304 g_object_unref (into);
1305 if (new_folder != NULL)
1306 g_object_unref (new_folder);
1308 /* Notify about operation end */
1309 modest_mail_operation_notify_end (self);
1313 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1315 TnyFolderStore *parent,
1316 gboolean delete_original)
1318 ModestMailOperationPrivate *priv = NULL;
1319 ModestTnyFolderRules parent_rules, rules;
1321 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1322 g_return_if_fail (TNY_IS_FOLDER (folder));
1323 g_return_if_fail (TNY_IS_FOLDER (parent));
1325 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1327 /* Get account and set it into mail_operation */
1328 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1329 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1331 /* Get folder rules */
1332 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1333 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1335 if (!TNY_IS_FOLDER_STORE (parent)) {
1339 /* The moveable restriction is applied also to copy operation */
1340 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1341 /* Set status failed and set an error */
1342 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1343 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1344 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1345 _("mail_in_ui_folder_move_target_error"));
1347 /* Notify the queue */
1348 modest_mail_operation_notify_end (self);
1349 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1350 /* Set status failed and set an error */
1351 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1352 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1353 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1354 _("FIXME: parent folder does not accept new folders"));
1356 /* Notify the queue */
1357 modest_mail_operation_notify_end (self);
1359 /* Pick references for async calls */
1360 g_object_ref (folder);
1361 g_object_ref (parent);
1363 /* Move/Copy folder */
1364 tny_folder_copy_async (folder,
1366 tny_folder_get_name (folder),
1369 transfer_folder_status_cb,
1375 modest_mail_operation_rename_folder (ModestMailOperation *self,
1379 ModestMailOperationPrivate *priv;
1380 ModestTnyFolderRules rules;
1382 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1383 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1384 g_return_if_fail (name);
1386 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1388 /* Get account and set it into mail_operation */
1389 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1391 /* Check folder rules */
1392 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1393 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1394 /* Set status failed and set an error */
1395 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1396 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1397 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1398 _("FIXME: unable to rename"));
1400 /* Notify about operation end */
1401 modest_mail_operation_notify_end (self);
1403 /* Rename. Camel handles folder subscription/unsubscription */
1404 TnyFolderStore *into;
1406 into = tny_folder_get_folder_store (folder);
1407 tny_folder_copy_async (folder, into, name, TRUE,
1409 transfer_folder_status_cb,
1412 g_object_unref (into);
1417 /* ******************************************************************* */
1418 /* ************************** MSG ACTIONS ************************* */
1419 /* ******************************************************************* */
1421 void modest_mail_operation_get_msg (ModestMailOperation *self,
1423 GetMsgAsyncUserCallback user_callback,
1426 GetMsgAsyncHelper *helper = NULL;
1428 ModestMailOperationPrivate *priv;
1430 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1431 g_return_if_fail (TNY_IS_HEADER (header));
1433 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1434 folder = tny_header_get_folder (header);
1436 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1438 /* Get message from folder */
1440 /* Get account and set it into mail_operation */
1441 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1443 helper = g_slice_new0 (GetMsgAsyncHelper);
1444 helper->mail_op = self;
1445 helper->user_callback = user_callback;
1446 helper->pending_ops = 1;
1447 helper->user_data = user_data;
1449 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1451 g_object_unref (G_OBJECT (folder));
1453 /* Set status failed and set an error */
1454 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1455 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1456 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1457 _("Error trying to get a message. No folder found for header"));
1459 /* Notify the queue */
1460 modest_mail_operation_notify_end (self);
1465 get_msg_cb (TnyFolder *folder,
1471 GetMsgAsyncHelper *helper = NULL;
1472 ModestMailOperation *self = NULL;
1473 ModestMailOperationPrivate *priv = NULL;
1475 helper = (GetMsgAsyncHelper *) user_data;
1476 g_return_if_fail (helper != NULL);
1477 self = helper->mail_op;
1478 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1479 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1481 helper->pending_ops--;
1483 /* Check errors and cancel */
1485 priv->error = g_error_copy (*error);
1486 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1490 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1491 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1492 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1493 _("Error trying to refresh the contents of %s"),
1494 tny_folder_get_name (folder));
1498 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1500 /* If user defined callback function was defined, call it */
1501 if (helper->user_callback) {
1502 helper->user_callback (self, NULL, msg, helper->user_data);
1507 if (helper->pending_ops == 0) {
1508 g_slice_free (GetMsgAsyncHelper, helper);
1510 /* Notify about operation end */
1511 modest_mail_operation_notify_end (self);
1516 get_msg_status_cb (GObject *obj,
1520 GetMsgAsyncHelper *helper = NULL;
1521 ModestMailOperation *self;
1522 ModestMailOperationPrivate *priv;
1523 ModestMailOperationState *state;
1525 g_return_if_fail (status != NULL);
1526 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1528 helper = (GetMsgAsyncHelper *) user_data;
1529 g_return_if_fail (helper != NULL);
1531 self = helper->mail_op;
1532 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1534 if ((status->position == 1) && (status->of_total == 100))
1540 state = modest_mail_operation_clone_state (self);
1541 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1542 g_slice_free (ModestMailOperationState, state);
1545 /****************************************************/
1547 ModestMailOperation *mail_op;
1549 GetMsgAsyncUserCallback user_callback;
1551 GDestroyNotify notify;
1555 GetMsgAsyncUserCallback user_callback;
1559 ModestMailOperation *mail_op;
1560 } NotifyGetMsgsInfo;
1564 * Used by get_msgs_full_thread to call the user_callback for each
1565 * message that has been read
1568 notify_get_msgs_full (gpointer data)
1570 NotifyGetMsgsInfo *info;
1572 info = (NotifyGetMsgsInfo *) data;
1574 /* Call the user callback */
1575 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1577 g_slice_free (NotifyGetMsgsInfo, info);
1583 * Used by get_msgs_full_thread to free al the thread resources and to
1584 * call the destroy function for the passed user_data
1587 get_msgs_full_destroyer (gpointer data)
1589 GetFullMsgsInfo *info;
1591 info = (GetFullMsgsInfo *) data;
1594 info->notify (info->user_data);
1597 g_object_unref (info->headers);
1598 g_slice_free (GetFullMsgsInfo, info);
1604 get_msgs_full_thread (gpointer thr_user_data)
1606 GetFullMsgsInfo *info;
1607 ModestMailOperationPrivate *priv = NULL;
1608 TnyIterator *iter = NULL;
1610 info = (GetFullMsgsInfo *) thr_user_data;
1611 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1613 iter = tny_list_create_iterator (info->headers);
1614 while (!tny_iterator_is_done (iter)) {
1618 header = TNY_HEADER (tny_iterator_get_current (iter));
1619 folder = tny_header_get_folder (header);
1621 /* Get message from folder */
1624 /* The callback will call it per each header */
1625 msg = tny_folder_get_msg (folder, header, &(priv->error));
1628 ModestMailOperationState *state;
1633 /* notify progress */
1634 state = modest_mail_operation_clone_state (info->mail_op);
1635 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1636 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1637 pair, (GDestroyNotify) modest_pair_free);
1639 /* The callback is the responsible for
1640 freeing the message */
1641 if (info->user_callback) {
1642 NotifyGetMsgsInfo *info_notify;
1643 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1644 info_notify->user_callback = info->user_callback;
1645 info_notify->mail_op = info->mail_op;
1646 info_notify->header = g_object_ref (header);
1647 info_notify->msg = g_object_ref (msg);
1648 info_notify->user_data = info->user_data;
1649 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1650 notify_get_msgs_full,
1653 g_object_unref (msg);
1656 /* Set status failed and set an error */
1657 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1658 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1659 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1660 "Error trying to get a message. No folder found for header");
1662 g_object_unref (header);
1663 tny_iterator_next (iter);
1666 /* Set operation status */
1667 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1668 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1670 /* Notify about operation end */
1671 g_idle_add (notify_update_account_queue, info->mail_op);
1673 /* Free thread resources. Will be called after all previous idles */
1674 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1680 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1681 TnyList *header_list,
1682 GetMsgAsyncUserCallback user_callback,
1684 GDestroyNotify notify)
1686 TnyHeader *header = NULL;
1687 TnyFolder *folder = NULL;
1689 ModestMailOperationPrivate *priv = NULL;
1690 GetFullMsgsInfo *info = NULL;
1691 gboolean size_ok = TRUE;
1693 TnyIterator *iter = NULL;
1695 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1697 /* Init mail operation */
1698 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1699 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1701 priv->total = tny_list_get_length(header_list);
1703 /* Get account and set it into mail_operation */
1704 if (tny_list_get_length (header_list) >= 1) {
1705 iter = tny_list_create_iterator (header_list);
1706 header = TNY_HEADER (tny_iterator_get_current (iter));
1707 folder = tny_header_get_folder (header);
1708 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1709 g_object_unref (header);
1710 g_object_unref (folder);
1712 if (tny_list_get_length (header_list) == 1) {
1713 g_object_unref (iter);
1718 /* Get msg size limit */
1719 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1720 MODEST_CONF_MSG_SIZE_LIMIT,
1723 g_clear_error (&(priv->error));
1724 max_size = G_MAXINT;
1726 max_size = max_size * KB;
1729 /* Check message size limits. If there is only one message
1730 always retrieve it */
1732 while (!tny_iterator_is_done (iter) && size_ok) {
1733 header = TNY_HEADER (tny_iterator_get_current (iter));
1734 if (tny_header_get_message_size (header) >= max_size)
1736 g_object_unref (header);
1737 tny_iterator_next (iter);
1739 g_object_unref (iter);
1743 /* Create the info */
1744 info = g_slice_new0 (GetFullMsgsInfo);
1745 info->mail_op = self;
1746 info->user_callback = user_callback;
1747 info->user_data = user_data;
1748 info->headers = g_object_ref (header_list);
1749 info->notify = notify;
1751 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1753 /* Set status failed and set an error */
1754 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1755 /* FIXME: the error msg is different for pop */
1756 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1757 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1758 _("emev_ni_ui_imap_msg_size_exceed_error"));
1759 /* Remove from queue and free resources */
1760 modest_mail_operation_notify_end (self);
1768 modest_mail_operation_remove_msg (ModestMailOperation *self,
1770 gboolean remove_to_trash)
1773 ModestMailOperationPrivate *priv;
1775 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1776 g_return_if_fail (TNY_IS_HEADER (header));
1778 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1779 folder = tny_header_get_folder (header);
1781 /* Get account and set it into mail_operation */
1782 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1784 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1786 /* Delete or move to trash */
1787 if (remove_to_trash) {
1788 TnyFolder *trash_folder;
1789 TnyStoreAccount *store_account;
1791 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1792 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1793 TNY_FOLDER_TYPE_TRASH);
1798 headers = tny_simple_list_new ();
1799 tny_list_append (headers, G_OBJECT (header));
1800 g_object_unref (header);
1803 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1804 g_object_unref (headers);
1805 /* g_object_unref (trash_folder); */
1807 ModestMailOperationPrivate *priv;
1809 /* Set status failed and set an error */
1810 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1811 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1812 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1813 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1814 _("Error trying to delete a message. Trash folder not found"));
1817 g_object_unref (G_OBJECT (store_account));
1819 tny_folder_remove_msg (folder, header, &(priv->error));
1821 tny_folder_sync(folder, TRUE, &(priv->error));
1826 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1828 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1831 g_object_unref (G_OBJECT (folder));
1833 /* Notify about operation end */
1834 modest_mail_operation_notify_end (self);
1838 transfer_msgs_status_cb (GObject *obj,
1842 XFerMsgAsyncHelper *helper = NULL;
1843 ModestMailOperation *self;
1844 ModestMailOperationPrivate *priv;
1845 ModestMailOperationState *state;
1848 g_return_if_fail (status != NULL);
1849 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1851 helper = (XFerMsgAsyncHelper *) user_data;
1852 g_return_if_fail (helper != NULL);
1854 self = helper->mail_op;
1855 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1857 if ((status->position == 1) && (status->of_total == 100))
1860 priv->done = status->position;
1861 priv->total = status->of_total;
1863 state = modest_mail_operation_clone_state (self);
1864 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1865 g_slice_free (ModestMailOperationState, state);
1870 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1872 XFerMsgAsyncHelper *helper;
1873 ModestMailOperation *self;
1874 ModestMailOperationPrivate *priv;
1876 helper = (XFerMsgAsyncHelper *) user_data;
1877 self = helper->mail_op;
1879 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1882 priv->error = g_error_copy (*err);
1884 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1885 } else if (cancelled) {
1886 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1887 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1888 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1889 _("Error trying to refresh the contents of %s"),
1890 tny_folder_get_name (folder));
1893 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1896 /* If user defined callback function was defined, call it */
1897 if (helper->user_callback) {
1898 helper->user_callback (priv->source, helper->user_data);
1902 g_object_unref (helper->headers);
1903 g_object_unref (helper->dest_folder);
1904 g_object_unref (helper->mail_op);
1905 g_slice_free (XFerMsgAsyncHelper, helper);
1906 g_object_unref (folder);
1908 /* Notify about operation end */
1909 modest_mail_operation_notify_end (self);
1913 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1916 gboolean delete_original,
1917 XferMsgsAsynUserCallback user_callback,
1920 ModestMailOperationPrivate *priv;
1922 TnyFolder *src_folder;
1923 XFerMsgAsyncHelper *helper;
1925 ModestTnyFolderRules rules;
1927 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1928 g_return_if_fail (TNY_IS_LIST (headers));
1929 g_return_if_fail (TNY_IS_FOLDER (folder));
1931 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1934 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1936 /* Apply folder rules */
1937 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1939 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1940 /* Set status failed and set an error */
1941 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1942 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1943 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1944 _("FIXME: folder does not accept msgs"));
1945 /* Notify the queue */
1946 modest_mail_operation_notify_end (self);
1950 /* Create the helper */
1951 helper = g_slice_new0 (XFerMsgAsyncHelper);
1952 helper->mail_op = g_object_ref(self);
1953 helper->dest_folder = g_object_ref(folder);
1954 helper->headers = g_object_ref(headers);
1955 helper->user_callback = user_callback;
1956 helper->user_data = user_data;
1958 /* Get source folder */
1959 iter = tny_list_create_iterator (headers);
1960 header = TNY_HEADER (tny_iterator_get_current (iter));
1961 src_folder = tny_header_get_folder (header);
1962 g_object_unref (header);
1963 g_object_unref (iter);
1965 /* Get account and set it into mail_operation */
1966 priv->account = modest_tny_folder_get_account (src_folder);
1968 /* Transfer messages */
1969 tny_folder_transfer_msgs_async (src_folder,
1974 transfer_msgs_status_cb,
1980 on_refresh_folder (TnyFolder *folder,
1985 RefreshAsyncHelper *helper = NULL;
1986 ModestMailOperation *self = NULL;
1987 ModestMailOperationPrivate *priv = NULL;
1989 helper = (RefreshAsyncHelper *) user_data;
1990 self = helper->mail_op;
1991 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1994 priv->error = g_error_copy (*error);
1995 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2000 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2001 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2002 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2003 _("Error trying to refresh the contents of %s"),
2004 tny_folder_get_name (folder));
2008 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2010 /* Call user defined callback, if it exists */
2011 if (helper->user_callback)
2012 helper->user_callback (priv->source, folder, helper->user_data);
2016 g_object_unref (helper->mail_op);
2017 g_slice_free (RefreshAsyncHelper, helper);
2018 g_object_unref (folder);
2020 /* Notify about operation end */
2021 modest_mail_operation_notify_end (self);
2025 on_refresh_folder_status_update (GObject *obj,
2029 RefreshAsyncHelper *helper = NULL;
2030 ModestMailOperation *self = NULL;
2031 ModestMailOperationPrivate *priv = NULL;
2032 ModestMailOperationState *state;
2034 g_return_if_fail (user_data != NULL);
2035 g_return_if_fail (status != NULL);
2036 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2038 helper = (RefreshAsyncHelper *) user_data;
2039 self = helper->mail_op;
2040 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2042 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2044 priv->done = status->position;
2045 priv->total = status->of_total;
2047 state = modest_mail_operation_clone_state (self);
2048 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2049 g_slice_free (ModestMailOperationState, state);
2053 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2055 RefreshAsyncUserCallback user_callback,
2058 ModestMailOperationPrivate *priv = NULL;
2059 RefreshAsyncHelper *helper = NULL;
2061 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2063 /* Pick a reference */
2064 g_object_ref (folder);
2066 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2068 /* Get account and set it into mail_operation */
2069 priv->account = modest_tny_folder_get_account (folder);
2071 /* Create the helper */
2072 helper = g_slice_new0 (RefreshAsyncHelper);
2073 helper->mail_op = g_object_ref(self);
2074 helper->user_callback = user_callback;
2075 helper->user_data = user_data;
2077 /* Refresh the folder. TODO: tinymail could issue a status
2078 updates before the callback call then this could happen. We
2079 must review the design */
2080 tny_folder_refresh_async (folder,
2082 on_refresh_folder_status_update,
2088 * It's used by the mail operation queue to notify the observers
2089 * attached to that signal that the operation finished. We need to use
2090 * that because tinymail does not give us the progress of a given
2091 * operation when it finishes (it directly calls the operation
2095 modest_mail_operation_notify_end (ModestMailOperation *self)
2097 ModestMailOperationState *state;
2099 /* Notify the observers about the mail opertation end */
2100 state = modest_mail_operation_clone_state (self);
2101 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2102 g_slice_free (ModestMailOperationState, state);