2 /* Copyright (c) 2006, Nokia Corporation
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of the Nokia Corporation nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <tny-mime-part.h>
34 #include <tny-store-account.h>
35 #include <tny-folder-store.h>
36 #include <tny-folder-store-query.h>
37 #include <tny-camel-stream.h>
38 #include <tny-camel-pop-store-account.h>
39 #include <tny-simple-list.h>
40 #include <tny-send-queue.h>
41 #include <tny-status.h>
42 #include <tny-folder-observer.h>
43 #include <camel/camel-stream-mem.h>
44 #include <glib/gi18n.h>
45 #include "modest-platform.h"
46 #include <modest-tny-account.h>
47 #include <modest-tny-send-queue.h>
48 #include <modest-runtime.h>
49 #include "modest-text-utils.h"
50 #include "modest-tny-msg.h"
51 #include "modest-tny-folder.h"
52 #include "modest-tny-platform-factory.h"
53 #include "modest-marshal.h"
54 #include "modest-error.h"
55 #include "modest-mail-operation.h"
59 /* 'private'/'protected' functions */
60 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
61 static void modest_mail_operation_init (ModestMailOperation *obj);
62 static void modest_mail_operation_finalize (GObject *obj);
64 static void get_msg_cb (TnyFolder *folder,
70 static void get_msg_status_cb (GObject *obj,
74 static void modest_mail_operation_notify_end (ModestMailOperation *self);
76 static gboolean did_a_cancel = FALSE;
78 enum _ModestMailOperationSignals
80 PROGRESS_CHANGED_SIGNAL,
85 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
86 struct _ModestMailOperationPrivate {
92 ErrorCheckingUserCallback error_checking;
93 gpointer error_checking_user_data;
94 ModestMailOperationStatus status;
95 ModestMailOperationTypeOperation op_type;
98 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
99 MODEST_TYPE_MAIL_OPERATION, \
100 ModestMailOperationPrivate))
102 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
103 priv->status = new_status;\
106 typedef struct _GetMsgAsyncHelper {
107 ModestMailOperation *mail_op;
108 GetMsgAsyncUserCallback user_callback;
112 typedef struct _RefreshAsyncHelper {
113 ModestMailOperation *mail_op;
114 RefreshAsyncUserCallback user_callback;
116 } RefreshAsyncHelper;
118 typedef struct _XFerMsgAsyncHelper
120 ModestMailOperation *mail_op;
122 TnyFolder *dest_folder;
123 XferMsgsAsynUserCallback user_callback;
125 } XFerMsgAsyncHelper;
128 static GObjectClass *parent_class = NULL;
130 static guint signals[NUM_SIGNALS] = {0};
133 modest_mail_operation_get_type (void)
135 static GType my_type = 0;
137 static const GTypeInfo my_info = {
138 sizeof(ModestMailOperationClass),
139 NULL, /* base init */
140 NULL, /* base finalize */
141 (GClassInitFunc) modest_mail_operation_class_init,
142 NULL, /* class finalize */
143 NULL, /* class data */
144 sizeof(ModestMailOperation),
146 (GInstanceInitFunc) modest_mail_operation_init,
149 my_type = g_type_register_static (G_TYPE_OBJECT,
150 "ModestMailOperation",
157 modest_mail_operation_class_init (ModestMailOperationClass *klass)
159 GObjectClass *gobject_class;
160 gobject_class = (GObjectClass*) klass;
162 parent_class = g_type_class_peek_parent (klass);
163 gobject_class->finalize = modest_mail_operation_finalize;
165 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
168 * ModestMailOperation::progress-changed
169 * @self: the #MailOperation that emits the signal
170 * @user_data: user data set when the signal handler was connected
172 * Emitted when the progress of a mail operation changes
174 signals[PROGRESS_CHANGED_SIGNAL] =
175 g_signal_new ("progress-changed",
176 G_TYPE_FROM_CLASS (gobject_class),
178 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
180 g_cclosure_marshal_VOID__POINTER,
181 G_TYPE_NONE, 1, G_TYPE_POINTER);
186 modest_mail_operation_init (ModestMailOperation *obj)
188 ModestMailOperationPrivate *priv;
190 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
192 priv->account = NULL;
193 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
194 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
199 priv->error_checking = NULL;
200 priv->error_checking_user_data = NULL;
204 modest_mail_operation_finalize (GObject *obj)
206 ModestMailOperationPrivate *priv;
208 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
211 g_error_free (priv->error);
215 g_object_unref (priv->source);
219 g_object_unref (priv->account);
220 priv->account = NULL;
224 G_OBJECT_CLASS(parent_class)->finalize (obj);
228 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
231 ModestMailOperation *obj;
232 ModestMailOperationPrivate *priv;
234 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
235 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
237 priv->op_type = op_type;
239 priv->source = g_object_ref(source);
245 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
247 ErrorCheckingUserCallback error_handler,
250 ModestMailOperation *obj;
251 ModestMailOperationPrivate *priv;
253 obj = modest_mail_operation_new (op_type, source);
254 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
256 g_return_val_if_fail (error_handler != NULL, obj);
257 priv->error_checking = error_handler;
263 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
265 ModestMailOperationPrivate *priv;
267 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
268 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
270 if (priv->error_checking != NULL)
271 priv->error_checking (self, priv->error_checking_user_data);
275 ModestMailOperationTypeOperation
276 modest_mail_operation_get_type_operation (ModestMailOperation *self)
278 ModestMailOperationPrivate *priv;
280 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
282 return priv->op_type;
286 modest_mail_operation_is_mine (ModestMailOperation *self,
289 ModestMailOperationPrivate *priv;
291 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
292 if (priv->source == NULL) return FALSE;
294 return priv->source == me;
298 modest_mail_operation_get_source (ModestMailOperation *self)
300 ModestMailOperationPrivate *priv;
302 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
304 return g_object_ref (priv->source);
307 ModestMailOperationStatus
308 modest_mail_operation_get_status (ModestMailOperation *self)
310 ModestMailOperationPrivate *priv;
312 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
313 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
314 MODEST_MAIL_OPERATION_STATUS_INVALID);
316 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
321 modest_mail_operation_get_error (ModestMailOperation *self)
323 ModestMailOperationPrivate *priv;
325 g_return_val_if_fail (self, NULL);
326 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
328 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
333 modest_mail_operation_cancel (ModestMailOperation *self)
335 ModestMailOperationPrivate *priv;
337 if (!MODEST_IS_MAIL_OPERATION (self)) {
338 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
342 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
344 /* cancel current operation in account */
345 //tny_account_cancel (priv->account);
350 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
352 /* Notify about operation end */
353 modest_mail_operation_notify_end (self);
359 modest_mail_operation_get_task_done (ModestMailOperation *self)
361 ModestMailOperationPrivate *priv;
363 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
365 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
370 modest_mail_operation_get_task_total (ModestMailOperation *self)
372 ModestMailOperationPrivate *priv;
374 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
376 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
381 modest_mail_operation_is_finished (ModestMailOperation *self)
383 ModestMailOperationPrivate *priv;
384 gboolean retval = FALSE;
386 if (!MODEST_IS_MAIL_OPERATION (self)) {
387 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
391 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
393 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
394 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
395 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
396 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
406 modest_mail_operation_get_id (ModestMailOperation *self)
408 ModestMailOperationPrivate *priv;
410 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
412 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
417 modest_mail_operation_set_id (ModestMailOperation *self,
420 ModestMailOperationPrivate *priv;
422 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
424 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
429 * Creates an image of the current state of a mail operation, the
430 * caller must free it
432 static ModestMailOperationState *
433 modest_mail_operation_clone_state (ModestMailOperation *self)
435 ModestMailOperationState *state;
436 ModestMailOperationPrivate *priv;
438 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
440 state = g_slice_new (ModestMailOperationState);
442 state->status = priv->status;
443 state->op_type = priv->op_type;
444 state->done = priv->done;
445 state->total = priv->total;
446 state->finished = modest_mail_operation_is_finished (self);
451 /* ******************************************************************* */
452 /* ************************** SEND ACTIONS ************************* */
453 /* ******************************************************************* */
456 modest_mail_operation_send_mail (ModestMailOperation *self,
457 TnyTransportAccount *transport_account,
460 TnySendQueue *send_queue = NULL;
461 ModestMailOperationPrivate *priv;
463 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
464 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
465 g_return_if_fail (TNY_IS_MSG (msg));
467 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
469 /* Get account and set it into mail_operation */
470 priv->account = g_object_ref (transport_account);
472 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
473 if (!TNY_IS_SEND_QUEUE(send_queue)) {
474 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
475 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
476 "modest: could not find send queue for account\n");
478 tny_send_queue_add (send_queue, msg, &(priv->error));
481 /* Notify about operation end */
482 modest_mail_operation_notify_end (self);
486 modest_mail_operation_send_new_mail (ModestMailOperation *self,
487 TnyTransportAccount *transport_account,
489 const gchar *from, const gchar *to,
490 const gchar *cc, const gchar *bcc,
491 const gchar *subject, const gchar *plain_body,
492 const gchar *html_body,
493 const GList *attachments_list,
494 TnyHeaderFlags priority_flags)
496 TnyMsg *new_msg = NULL;
497 TnyFolder *folder = NULL;
498 TnyHeader *header = NULL;
499 ModestMailOperationPrivate *priv = NULL;
501 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
502 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
504 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
506 /* Get account and set it into mail_operation */
507 priv->account = g_object_ref (transport_account);
509 /* Check parametters */
511 /* Set status failed and set an error */
512 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
513 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
514 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
515 _("Error trying to send a mail. You need to set at least one recipient"));
519 if (html_body == NULL) {
520 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
522 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
525 g_printerr ("modest: failed to create a new msg\n");
529 /* Set priority flags in message */
530 header = tny_msg_get_header (new_msg);
531 if (priority_flags != 0)
532 tny_header_set_flags (header, priority_flags);
534 /* Call mail operation */
535 modest_mail_operation_send_mail (self, transport_account, new_msg);
537 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
539 if (draft_msg != NULL) {
540 header = tny_msg_get_header (draft_msg);
541 /* Note: This can fail (with a warning) if the message is not really already in a folder,
542 * because this function requires it to have a UID. */
543 tny_folder_remove_msg (folder, header, NULL);
544 g_object_unref (header);
549 g_object_unref (G_OBJECT (new_msg));
553 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
554 TnyTransportAccount *transport_account,
556 const gchar *from, const gchar *to,
557 const gchar *cc, const gchar *bcc,
558 const gchar *subject, const gchar *plain_body,
559 const gchar *html_body,
560 const GList *attachments_list,
561 TnyHeaderFlags priority_flags)
564 TnyFolder *folder = NULL;
565 TnyHeader *header = NULL;
566 ModestMailOperationPrivate *priv = NULL;
568 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
569 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
571 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
573 /* Get account and set it into mail_operation */
574 priv->account = g_object_ref (transport_account);
576 if (html_body == NULL) {
577 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
579 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
582 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
583 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
584 "modest: failed to create a new msg\n");
588 /* add priority flags */
589 header = tny_msg_get_header (msg);
590 tny_header_set_flags (header, priority_flags);
592 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
594 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
595 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
596 "modest: failed to create a new msg\n");
600 if (draft_msg != NULL) {
601 header = tny_msg_get_header (draft_msg);
602 /* Remove the old draft expunging it */
603 tny_folder_remove_msg (folder, header, NULL);
604 tny_folder_sync (folder, TRUE, NULL);
605 g_object_unref (header);
608 tny_folder_add_msg (folder, msg, &(priv->error));
614 g_object_unref (G_OBJECT(msg));
616 g_object_unref (G_OBJECT(folder));
618 modest_mail_operation_notify_end (self);
623 ModestMailOperation *mail_op;
624 TnyStoreAccount *account;
625 TnyTransportAccount *transport_account;
628 gchar *retrieve_type;
631 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
632 /* We use this folder observer to track the headers that have been
633 * added to a folder */
636 TnyList *new_headers;
637 } InternalFolderObserver;
641 } InternalFolderObserverClass;
643 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
645 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
646 internal_folder_observer,
648 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
652 foreach_add_item (gpointer header, gpointer user_data)
654 /* printf("DEBUG: %s: header subject=%s\n",
655 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
657 tny_list_prepend (TNY_LIST (user_data),
658 g_object_ref (G_OBJECT (header)));
661 /* This is the method that looks for new messages in a folder */
663 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
665 InternalFolderObserver *derived = (InternalFolderObserver *)self;
667 TnyFolderChangeChanged changed;
669 changed = tny_folder_change_get_changed (change);
671 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
674 /* Get added headers */
675 list = tny_simple_list_new ();
676 tny_folder_change_get_added_headers (change, list);
678 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
679 * __FUNCTION__, tny_list_get_length(list));
682 /* Add them to the folder observer */
683 tny_list_foreach (list, foreach_add_item,
684 derived->new_headers);
686 g_object_unref (G_OBJECT (list));
691 internal_folder_observer_init (InternalFolderObserver *self)
693 self->new_headers = tny_simple_list_new ();
696 internal_folder_observer_finalize (GObject *object)
698 InternalFolderObserver *self;
700 self = (InternalFolderObserver *) object;
701 g_object_unref (self->new_headers);
703 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
706 tny_folder_observer_init (TnyFolderObserverIface *iface)
708 iface->update_func = internal_folder_observer_update;
711 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
713 GObjectClass *object_class;
715 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
716 object_class = (GObjectClass*) klass;
717 object_class->finalize = internal_folder_observer_finalize;
723 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
726 TnyList *folders = tny_simple_list_new ();
728 tny_folder_store_get_folders (store, folders, query, NULL);
729 iter = tny_list_create_iterator (folders);
731 while (!tny_iterator_is_done (iter)) {
733 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
735 tny_list_prepend (all_folders, G_OBJECT (folder));
736 recurse_folders (folder, query, all_folders);
737 g_object_unref (G_OBJECT (folder));
739 tny_iterator_next (iter);
741 g_object_unref (G_OBJECT (iter));
742 g_object_unref (G_OBJECT (folders));
746 * Issues the "progress-changed" signal. The timer won't be removed,
747 * so you must call g_source_remove to stop the signal emission
750 idle_notify_progress (gpointer data)
752 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
753 ModestMailOperationState *state;
755 state = modest_mail_operation_clone_state (mail_op);
756 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
757 g_slice_free (ModestMailOperationState, state);
763 * Issues the "progress-changed" signal and removes the timer. It uses
764 * a lock to ensure that the progress information of the mail
765 * operation is not modified while there are notifications pending
768 idle_notify_progress_once (gpointer data)
772 pair = (ModestPair *) data;
774 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
776 /* Free the state and the reference to the mail operation */
777 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
778 g_object_unref (pair->first);
784 * Used by update_account_thread to notify the queue from the main
785 * loop. We call it inside an idle call to achieve that
788 notify_update_account_queue (gpointer data)
790 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
791 ModestMailOperationPrivate *priv = NULL;
793 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
795 modest_mail_operation_notify_end (mail_op);
796 g_object_unref (mail_op);
802 compare_headers_by_date (gconstpointer a,
805 TnyHeader **header1, **header2;
808 header1 = (TnyHeader **) a;
809 header2 = (TnyHeader **) b;
811 sent1 = tny_header_get_date_sent (*header1);
812 sent2 = tny_header_get_date_sent (*header2);
814 /* We want the most recent ones (greater time_t) at the
823 set_last_updated_idle (gpointer data)
825 /* It does not matter if the time is not exactly the same than
826 the time when this idle was called, it's just an
827 approximation and it won't be very different */
828 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
830 MODEST_ACCOUNT_LAST_UPDATED,
838 update_account_thread (gpointer thr_user_data)
840 UpdateAccountInfo *info;
841 TnyList *all_folders = NULL;
842 GPtrArray *new_headers;
843 TnyIterator *iter = NULL;
844 TnyFolderStoreQuery *query = NULL;
845 ModestMailOperationPrivate *priv;
846 ModestTnySendQueue *send_queue;
848 info = (UpdateAccountInfo *) thr_user_data;
849 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
851 /* Get account and set it into mail_operation */
852 priv->account = g_object_ref (info->account);
855 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
856 * show any updates unless we do that
858 if (TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
859 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
861 /* Get all the folders. We can do it synchronously because
862 we're already running in a different thread than the UI */
863 all_folders = tny_simple_list_new ();
864 query = tny_folder_store_query_new ();
865 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
866 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
871 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
875 iter = tny_list_create_iterator (all_folders);
876 while (!tny_iterator_is_done (iter)) {
877 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
879 recurse_folders (folder, query, all_folders);
880 tny_iterator_next (iter);
882 g_object_unref (G_OBJECT (iter));
884 /* Update status and notify. We need to call the notification
885 with a source function in order to call it from the main
886 loop. We need that in order not to get into trouble with
887 Gtk+. We use a timeout in order to provide more status
888 information, because the sync tinymail call does not
889 provide it for the moment */
890 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
892 /* Refresh folders */
893 new_headers = g_ptr_array_new ();
894 iter = tny_list_create_iterator (all_folders);
896 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
898 InternalFolderObserver *observer;
899 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
901 /* Refresh the folder */
902 /* Our observer receives notification of new emails during folder refreshes,
903 * so we can use observer->new_headers.
904 * TODO: This does not seem to be providing accurate numbers.
905 * Possibly the observer is notified asynchronously.
907 observer = g_object_new (internal_folder_observer_get_type (), NULL);
908 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
910 /* This gets the status information (headers) from the server.
911 * We use the blocking version, because we are already in a separate
915 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
916 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
919 /* If the retrieve type is full messages, refresh and get the messages */
920 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
922 iter = tny_list_create_iterator (observer->new_headers);
923 while (!tny_iterator_is_done (iter)) {
924 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
925 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
926 * __FUNCTION__, tny_account_get_id (priv->account),
927 * tny_header_get_subject (header));
930 /* Apply per-message size limits */
931 if (tny_header_get_message_size (header) < info->max_size)
932 g_ptr_array_add (new_headers, g_object_ref (header));
934 g_object_unref (header);
935 tny_iterator_next (iter);
937 g_object_unref (iter);
940 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
941 g_object_unref (observer);
945 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
947 g_object_unref (G_OBJECT (folder));
948 tny_iterator_next (iter);
951 did_a_cancel = FALSE;
953 g_object_unref (G_OBJECT (iter));
954 g_source_remove (timeout);
956 if (new_headers->len > 0) {
960 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
962 /* Apply message count limit */
963 /* If the number of messages exceeds the maximum, ask the
964 * user to download them all,
965 * as per the UI spec "Retrieval Limits" section in 4.4:
967 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
968 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
969 if (new_headers->len > info->retrieve_limit) {
970 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
971 * with 'Get all' and 'Newest only' buttons. */
972 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
973 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
974 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
975 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
976 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
981 priv->total = MIN (new_headers->len, info->retrieve_limit);
982 while (msg_num < priv->total) {
984 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
985 TnyFolder *folder = tny_header_get_folder (header);
986 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
987 ModestMailOperationState *state;
991 /* We can not just use the mail operation because the
992 values of done and total could change before the
994 state = modest_mail_operation_clone_state (info->mail_op);
995 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
996 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
997 pair, (GDestroyNotify) modest_pair_free);
999 g_object_unref (msg);
1000 g_object_unref (folder);
1004 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1005 g_ptr_array_free (new_headers, FALSE);
1009 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1012 if (priv->account != NULL)
1013 g_object_unref (priv->account);
1014 priv->account = g_object_ref (info->transport_account);
1016 send_queue = modest_runtime_get_send_queue (info->transport_account);
1018 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
1019 modest_tny_send_queue_try_to_send (send_queue);
1020 g_source_remove (timeout);
1022 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1023 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1024 "cannot create a send queue for %s\n",
1025 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1026 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1029 /* Check if the operation was a success */
1031 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1033 /* Update the last updated key */
1034 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1035 set_last_updated_idle,
1036 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1037 (GDestroyNotify) g_free);
1041 /* Notify about operation end. Note that the info could be
1042 freed before this idle happens, but the mail operation will
1044 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1047 g_object_unref (query);
1048 g_object_unref (all_folders);
1049 g_object_unref (info->account);
1050 g_object_unref (info->transport_account);
1051 g_free (info->retrieve_type);
1052 g_slice_free (UpdateAccountInfo, info);
1058 modest_mail_operation_update_account (ModestMailOperation *self,
1059 const gchar *account_name)
1062 UpdateAccountInfo *info;
1063 ModestMailOperationPrivate *priv;
1064 ModestAccountMgr *mgr;
1065 TnyStoreAccount *modest_account;
1066 TnyTransportAccount *transport_account;
1068 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1069 g_return_val_if_fail (account_name, FALSE);
1071 /* Make sure that we have a connection, and request one
1073 * TODO: Is there some way to trigger this for every attempt to
1074 * use the network? */
1075 if (!modest_platform_connect_and_wait(NULL))
1078 /* Init mail operation. Set total and done to 0, and do not
1079 update them, this way the progress objects will know that
1080 we have no clue about the number of the objects */
1081 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1084 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1086 /* Get the Modest account */
1087 modest_account = (TnyStoreAccount *)
1088 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1090 TNY_ACCOUNT_TYPE_STORE);
1092 if (!modest_account) {
1093 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1094 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1095 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1096 "cannot get tny store account for %s\n", account_name);
1097 modest_mail_operation_notify_end (self);
1103 /* Get the transport account, we can not do it in the thread
1104 due to some problems with dbus */
1105 transport_account = (TnyTransportAccount *)
1106 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1108 if (!transport_account) {
1109 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1110 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1111 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1112 "cannot get tny transport account for %s\n", account_name);
1113 modest_mail_operation_notify_end (self);
1118 /* Create the helper object */
1119 info = g_slice_new (UpdateAccountInfo);
1120 info->mail_op = self;
1121 info->account = modest_account;
1122 info->transport_account = transport_account;
1124 /* Get the message size limit */
1125 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1126 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1127 if (info->max_size == 0)
1128 info->max_size = G_MAXINT;
1130 info->max_size = info->max_size * KB;
1132 /* Get per-account retrieval type */
1133 mgr = modest_runtime_get_account_mgr ();
1134 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1135 MODEST_ACCOUNT_RETRIEVE, FALSE);
1137 /* Get per-account message amount retrieval limit */
1138 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1139 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1140 if (info->retrieve_limit == 0)
1141 info->retrieve_limit = G_MAXINT;
1143 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1145 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1150 /* ******************************************************************* */
1151 /* ************************** STORE ACTIONS ************************* */
1152 /* ******************************************************************* */
1156 modest_mail_operation_create_folder (ModestMailOperation *self,
1157 TnyFolderStore *parent,
1160 ModestMailOperationPrivate *priv;
1161 TnyFolder *new_folder = NULL;
1163 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1164 g_return_val_if_fail (name, NULL);
1166 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1169 if (TNY_IS_FOLDER (parent)) {
1170 /* Check folder rules */
1171 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1172 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1173 /* Set status failed and set an error */
1174 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1175 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1176 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1177 _("mail_in_ui_folder_create_error"));
1182 /* Create the folder */
1183 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1184 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1186 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1189 /* Notify about operation end */
1190 modest_mail_operation_notify_end (self);
1196 modest_mail_operation_remove_folder (ModestMailOperation *self,
1198 gboolean remove_to_trash)
1200 TnyAccount *account;
1201 ModestMailOperationPrivate *priv;
1202 ModestTnyFolderRules rules;
1204 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1205 g_return_if_fail (TNY_IS_FOLDER (folder));
1207 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1209 /* Check folder rules */
1210 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1211 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1212 /* Set status failed and set an error */
1213 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1214 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1215 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1216 _("mail_in_ui_folder_delete_error"));
1220 /* Get the account */
1221 account = modest_tny_folder_get_account (folder);
1222 priv->account = g_object_ref(account);
1224 /* Delete folder or move to trash */
1225 if (remove_to_trash) {
1226 TnyFolder *trash_folder = NULL;
1227 trash_folder = modest_tny_account_get_special_folder (account,
1228 TNY_FOLDER_TYPE_TRASH);
1229 /* TODO: error_handling */
1230 modest_mail_operation_xfer_folder (self, folder,
1231 TNY_FOLDER_STORE (trash_folder), TRUE);
1233 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1235 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1236 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1239 g_object_unref (G_OBJECT (parent));
1241 g_object_unref (G_OBJECT (account));
1244 /* Notify about operation end */
1245 modest_mail_operation_notify_end (self);
1249 transfer_folder_status_cb (GObject *obj,
1253 ModestMailOperation *self;
1254 ModestMailOperationPrivate *priv;
1255 ModestMailOperationState *state;
1257 g_return_if_fail (status != NULL);
1258 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1260 self = MODEST_MAIL_OPERATION (user_data);
1261 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1263 if ((status->position == 1) && (status->of_total == 100))
1266 priv->done = status->position;
1267 priv->total = status->of_total;
1269 state = modest_mail_operation_clone_state (self);
1270 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1271 g_slice_free (ModestMailOperationState, state);
1276 transfer_folder_cb (TnyFolder *folder,
1277 TnyFolderStore *into,
1279 TnyFolder *new_folder, GError **err,
1282 ModestMailOperation *self = NULL;
1283 ModestMailOperationPrivate *priv = NULL;
1285 self = MODEST_MAIL_OPERATION (user_data);
1287 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1290 priv->error = g_error_copy (*err);
1292 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1293 } else if (cancelled) {
1294 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1295 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1296 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1297 _("Transference of %s was cancelled."),
1298 tny_folder_get_name (folder));
1301 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1305 g_object_unref (folder);
1306 g_object_unref (into);
1307 if (new_folder != NULL)
1308 g_object_unref (new_folder);
1310 /* Notify about operation end */
1311 modest_mail_operation_notify_end (self);
1315 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1317 TnyFolderStore *parent,
1318 gboolean delete_original)
1320 ModestMailOperationPrivate *priv = NULL;
1321 ModestTnyFolderRules parent_rules, rules;
1323 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1324 g_return_if_fail (TNY_IS_FOLDER (folder));
1325 g_return_if_fail (TNY_IS_FOLDER (parent));
1327 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1329 /* Get account and set it into mail_operation */
1330 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1331 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1333 /* Get folder rules */
1334 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1335 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1337 if (!TNY_IS_FOLDER_STORE (parent)) {
1341 /* The moveable restriction is applied also to copy operation */
1342 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1343 /* Set status failed and set an error */
1344 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1345 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1346 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1347 _("mail_in_ui_folder_move_target_error"));
1349 /* Notify the queue */
1350 modest_mail_operation_notify_end (self);
1351 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1352 /* Set status failed and set an error */
1353 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1354 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1355 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1356 _("FIXME: parent folder does not accept new folders"));
1358 /* Notify the queue */
1359 modest_mail_operation_notify_end (self);
1361 /* Pick references for async calls */
1362 g_object_ref (folder);
1363 g_object_ref (parent);
1365 /* Move/Copy folder */
1366 tny_folder_copy_async (folder,
1368 tny_folder_get_name (folder),
1371 transfer_folder_status_cb,
1377 modest_mail_operation_rename_folder (ModestMailOperation *self,
1381 ModestMailOperationPrivate *priv;
1382 ModestTnyFolderRules rules;
1384 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1385 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1386 g_return_if_fail (name);
1388 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1390 /* Get account and set it into mail_operation */
1391 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1393 /* Check folder rules */
1394 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1395 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1396 /* Set status failed and set an error */
1397 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1398 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1399 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1400 _("FIXME: unable to rename"));
1402 /* Notify about operation end */
1403 modest_mail_operation_notify_end (self);
1405 /* Rename. Camel handles folder subscription/unsubscription */
1406 TnyFolderStore *into;
1408 into = tny_folder_get_folder_store (folder);
1409 tny_folder_copy_async (folder, into, name, TRUE,
1411 transfer_folder_status_cb,
1414 g_object_unref (into);
1419 /* ******************************************************************* */
1420 /* ************************** MSG ACTIONS ************************* */
1421 /* ******************************************************************* */
1423 void modest_mail_operation_get_msg (ModestMailOperation *self,
1425 GetMsgAsyncUserCallback user_callback,
1428 GetMsgAsyncHelper *helper = NULL;
1430 ModestMailOperationPrivate *priv;
1432 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1433 g_return_if_fail (TNY_IS_HEADER (header));
1435 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1436 folder = tny_header_get_folder (header);
1438 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1440 /* Get message from folder */
1442 /* Get account and set it into mail_operation */
1443 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1445 helper = g_slice_new0 (GetMsgAsyncHelper);
1446 helper->mail_op = self;
1447 helper->user_callback = user_callback;
1448 helper->user_data = user_data;
1450 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1452 g_object_unref (G_OBJECT (folder));
1454 /* Set status failed and set an error */
1455 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1456 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1457 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1458 _("Error trying to get a message. No folder found for header"));
1460 /* Notify the queue */
1461 modest_mail_operation_notify_end (self);
1466 get_msg_cb (TnyFolder *folder,
1472 GetMsgAsyncHelper *helper = NULL;
1473 ModestMailOperation *self = NULL;
1474 ModestMailOperationPrivate *priv = NULL;
1476 helper = (GetMsgAsyncHelper *) user_data;
1477 g_return_if_fail (helper != NULL);
1478 self = helper->mail_op;
1479 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1480 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1482 /* Check errors and cancel */
1484 priv->error = g_error_copy (*error);
1485 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1489 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1490 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1491 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1492 _("Error trying to refresh the contents of %s"),
1493 tny_folder_get_name (folder));
1497 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1499 /* If user defined callback function was defined, call it */
1500 if (helper->user_callback) {
1501 helper->user_callback (self, NULL, msg, helper->user_data);
1506 g_slice_free (GetMsgAsyncHelper, helper);
1508 /* Notify about operation end */
1509 modest_mail_operation_notify_end (self);
1513 get_msg_status_cb (GObject *obj,
1517 GetMsgAsyncHelper *helper = NULL;
1518 ModestMailOperation *self;
1519 ModestMailOperationPrivate *priv;
1520 ModestMailOperationState *state;
1522 g_return_if_fail (status != NULL);
1523 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1525 helper = (GetMsgAsyncHelper *) user_data;
1526 g_return_if_fail (helper != NULL);
1528 self = helper->mail_op;
1529 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1531 if ((status->position == 1) && (status->of_total == 100))
1537 state = modest_mail_operation_clone_state (self);
1538 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1539 g_slice_free (ModestMailOperationState, state);
1542 /****************************************************/
1544 ModestMailOperation *mail_op;
1546 GetMsgAsyncUserCallback user_callback;
1548 GDestroyNotify notify;
1552 GetMsgAsyncUserCallback user_callback;
1556 ModestMailOperation *mail_op;
1557 } NotifyGetMsgsInfo;
1561 * Used by get_msgs_full_thread to call the user_callback for each
1562 * message that has been read
1565 notify_get_msgs_full (gpointer data)
1567 NotifyGetMsgsInfo *info;
1569 info = (NotifyGetMsgsInfo *) data;
1571 /* Call the user callback */
1572 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1574 g_slice_free (NotifyGetMsgsInfo, info);
1580 * Used by get_msgs_full_thread to free al the thread resources and to
1581 * call the destroy function for the passed user_data
1584 get_msgs_full_destroyer (gpointer data)
1586 GetFullMsgsInfo *info;
1588 info = (GetFullMsgsInfo *) data;
1591 info->notify (info->user_data);
1594 g_object_unref (info->headers);
1595 g_slice_free (GetFullMsgsInfo, info);
1601 get_msgs_full_thread (gpointer thr_user_data)
1603 GetFullMsgsInfo *info;
1604 ModestMailOperationPrivate *priv = NULL;
1605 TnyIterator *iter = NULL;
1607 info = (GetFullMsgsInfo *) thr_user_data;
1608 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1610 iter = tny_list_create_iterator (info->headers);
1611 while (!tny_iterator_is_done (iter)) {
1615 header = TNY_HEADER (tny_iterator_get_current (iter));
1616 folder = tny_header_get_folder (header);
1618 /* Get message from folder */
1621 /* The callback will call it per each header */
1622 msg = tny_folder_get_msg (folder, header, &(priv->error));
1625 ModestMailOperationState *state;
1630 /* notify progress */
1631 state = modest_mail_operation_clone_state (info->mail_op);
1632 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1633 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1634 pair, (GDestroyNotify) modest_pair_free);
1636 /* The callback is the responsible for
1637 freeing the message */
1638 if (info->user_callback) {
1639 NotifyGetMsgsInfo *info_notify;
1640 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1641 info_notify->user_callback = info->user_callback;
1642 info_notify->mail_op = info->mail_op;
1643 info_notify->header = g_object_ref (header);
1644 info_notify->msg = g_object_ref (msg);
1645 info_notify->user_data = info->user_data;
1646 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1647 notify_get_msgs_full,
1650 g_object_unref (msg);
1653 /* Set status failed and set an error */
1654 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1655 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1656 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1657 "Error trying to get a message. No folder found for header");
1659 g_object_unref (header);
1660 tny_iterator_next (iter);
1663 /* Set operation status */
1664 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1665 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1667 /* Notify about operation end */
1668 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1670 /* Free thread resources. Will be called after all previous idles */
1671 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1677 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1678 TnyList *header_list,
1679 GetMsgAsyncUserCallback user_callback,
1681 GDestroyNotify notify)
1683 TnyHeader *header = NULL;
1684 TnyFolder *folder = NULL;
1686 ModestMailOperationPrivate *priv = NULL;
1687 GetFullMsgsInfo *info = NULL;
1688 gboolean size_ok = TRUE;
1690 TnyIterator *iter = NULL;
1692 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1694 /* Init mail operation */
1695 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1696 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1698 priv->total = tny_list_get_length(header_list);
1700 /* Get account and set it into mail_operation */
1701 if (tny_list_get_length (header_list) >= 1) {
1702 iter = tny_list_create_iterator (header_list);
1703 header = TNY_HEADER (tny_iterator_get_current (iter));
1704 folder = tny_header_get_folder (header);
1705 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1706 g_object_unref (header);
1707 g_object_unref (folder);
1709 if (tny_list_get_length (header_list) == 1) {
1710 g_object_unref (iter);
1715 /* Get msg size limit */
1716 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1717 MODEST_CONF_MSG_SIZE_LIMIT,
1720 g_clear_error (&(priv->error));
1721 max_size = G_MAXINT;
1723 max_size = max_size * KB;
1726 /* Check message size limits. If there is only one message
1727 always retrieve it */
1729 while (!tny_iterator_is_done (iter) && size_ok) {
1730 header = TNY_HEADER (tny_iterator_get_current (iter));
1731 if (tny_header_get_message_size (header) >= max_size)
1733 g_object_unref (header);
1734 tny_iterator_next (iter);
1736 g_object_unref (iter);
1740 /* Create the info */
1741 info = g_slice_new0 (GetFullMsgsInfo);
1742 info->mail_op = self;
1743 info->user_callback = user_callback;
1744 info->user_data = user_data;
1745 info->headers = g_object_ref (header_list);
1746 info->notify = notify;
1748 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1750 /* Set status failed and set an error */
1751 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1752 /* FIXME: the error msg is different for pop */
1753 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1754 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1755 _("emev_ni_ui_imap_msg_size_exceed_error"));
1756 /* Remove from queue and free resources */
1757 modest_mail_operation_notify_end (self);
1765 modest_mail_operation_remove_msg (ModestMailOperation *self,
1767 gboolean remove_to_trash)
1770 ModestMailOperationPrivate *priv;
1772 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1773 g_return_if_fail (TNY_IS_HEADER (header));
1775 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1776 folder = tny_header_get_folder (header);
1778 /* Get account and set it into mail_operation */
1779 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1781 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1783 /* Delete or move to trash */
1784 if (remove_to_trash) {
1785 TnyFolder *trash_folder;
1786 TnyStoreAccount *store_account;
1788 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1789 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1790 TNY_FOLDER_TYPE_TRASH);
1795 headers = tny_simple_list_new ();
1796 tny_list_append (headers, G_OBJECT (header));
1797 g_object_unref (header);
1800 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1801 g_object_unref (headers);
1802 /* g_object_unref (trash_folder); */
1804 ModestMailOperationPrivate *priv;
1806 /* Set status failed and set an error */
1807 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1808 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1809 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1810 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1811 _("Error trying to delete a message. Trash folder not found"));
1814 g_object_unref (G_OBJECT (store_account));
1816 tny_folder_remove_msg (folder, header, &(priv->error));
1818 tny_folder_sync(folder, TRUE, &(priv->error));
1823 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1825 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1828 g_object_unref (G_OBJECT (folder));
1830 /* Notify about operation end */
1831 modest_mail_operation_notify_end (self);
1835 transfer_msgs_status_cb (GObject *obj,
1839 XFerMsgAsyncHelper *helper = NULL;
1840 ModestMailOperation *self;
1841 ModestMailOperationPrivate *priv;
1842 ModestMailOperationState *state;
1845 g_return_if_fail (status != NULL);
1846 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1848 helper = (XFerMsgAsyncHelper *) user_data;
1849 g_return_if_fail (helper != NULL);
1851 self = helper->mail_op;
1852 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1854 if ((status->position == 1) && (status->of_total == 100))
1857 priv->done = status->position;
1858 priv->total = status->of_total;
1860 state = modest_mail_operation_clone_state (self);
1861 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1862 g_slice_free (ModestMailOperationState, state);
1867 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1869 XFerMsgAsyncHelper *helper;
1870 ModestMailOperation *self;
1871 ModestMailOperationPrivate *priv;
1873 helper = (XFerMsgAsyncHelper *) user_data;
1874 self = helper->mail_op;
1876 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1879 priv->error = g_error_copy (*err);
1881 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1882 } else if (cancelled) {
1883 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1884 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1885 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1886 _("Error trying to refresh the contents of %s"),
1887 tny_folder_get_name (folder));
1890 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1893 /* If user defined callback function was defined, call it */
1894 if (helper->user_callback) {
1895 helper->user_callback (priv->source, helper->user_data);
1899 g_object_unref (helper->headers);
1900 g_object_unref (helper->dest_folder);
1901 g_object_unref (helper->mail_op);
1902 g_slice_free (XFerMsgAsyncHelper, helper);
1903 g_object_unref (folder);
1905 /* Notify about operation end */
1906 modest_mail_operation_notify_end (self);
1910 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1913 gboolean delete_original,
1914 XferMsgsAsynUserCallback user_callback,
1917 ModestMailOperationPrivate *priv;
1919 TnyFolder *src_folder;
1920 XFerMsgAsyncHelper *helper;
1922 ModestTnyFolderRules rules;
1924 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1925 g_return_if_fail (TNY_IS_LIST (headers));
1926 g_return_if_fail (TNY_IS_FOLDER (folder));
1928 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1931 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1933 /* Apply folder rules */
1934 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1936 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1937 /* Set status failed and set an error */
1938 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1939 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1940 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1941 _("FIXME: folder does not accept msgs"));
1942 /* Notify the queue */
1943 modest_mail_operation_notify_end (self);
1947 /* Create the helper */
1948 helper = g_slice_new0 (XFerMsgAsyncHelper);
1949 helper->mail_op = g_object_ref(self);
1950 helper->dest_folder = g_object_ref(folder);
1951 helper->headers = g_object_ref(headers);
1952 helper->user_callback = user_callback;
1953 helper->user_data = user_data;
1955 /* Get source folder */
1956 iter = tny_list_create_iterator (headers);
1957 header = TNY_HEADER (tny_iterator_get_current (iter));
1958 src_folder = tny_header_get_folder (header);
1959 g_object_unref (header);
1960 g_object_unref (iter);
1962 /* Get account and set it into mail_operation */
1963 priv->account = modest_tny_folder_get_account (src_folder);
1965 /* Transfer messages */
1966 tny_folder_transfer_msgs_async (src_folder,
1971 transfer_msgs_status_cb,
1977 on_refresh_folder (TnyFolder *folder,
1982 RefreshAsyncHelper *helper = NULL;
1983 ModestMailOperation *self = NULL;
1984 ModestMailOperationPrivate *priv = NULL;
1986 helper = (RefreshAsyncHelper *) user_data;
1987 self = helper->mail_op;
1988 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1991 priv->error = g_error_copy (*error);
1992 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1997 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1998 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1999 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2000 _("Error trying to refresh the contents of %s"),
2001 tny_folder_get_name (folder));
2005 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2008 /* Call user defined callback, if it exists */
2009 if (helper->user_callback)
2010 helper->user_callback (priv->source, folder, helper->user_data);
2013 g_object_unref (helper->mail_op);
2014 g_slice_free (RefreshAsyncHelper, helper);
2015 g_object_unref (folder);
2017 /* Notify about operation end */
2018 modest_mail_operation_notify_end (self);
2022 on_refresh_folder_status_update (GObject *obj,
2026 RefreshAsyncHelper *helper = NULL;
2027 ModestMailOperation *self = NULL;
2028 ModestMailOperationPrivate *priv = NULL;
2029 ModestMailOperationState *state;
2031 g_return_if_fail (user_data != NULL);
2032 g_return_if_fail (status != NULL);
2033 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2035 helper = (RefreshAsyncHelper *) user_data;
2036 self = helper->mail_op;
2037 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2039 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2041 priv->done = status->position;
2042 priv->total = status->of_total;
2044 state = modest_mail_operation_clone_state (self);
2045 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2046 g_slice_free (ModestMailOperationState, state);
2050 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2052 RefreshAsyncUserCallback user_callback,
2055 ModestMailOperationPrivate *priv = NULL;
2056 RefreshAsyncHelper *helper = NULL;
2058 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2060 /* Pick a reference */
2061 g_object_ref (folder);
2063 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2065 /* Get account and set it into mail_operation */
2066 priv->account = modest_tny_folder_get_account (folder);
2068 /* Create the helper */
2069 helper = g_slice_new0 (RefreshAsyncHelper);
2070 helper->mail_op = g_object_ref(self);
2071 helper->user_callback = user_callback;
2072 helper->user_data = user_data;
2074 /* Refresh the folder. TODO: tinymail could issue a status
2075 updates before the callback call then this could happen. We
2076 must review the design */
2077 tny_folder_refresh_async (folder,
2079 on_refresh_folder_status_update,
2085 * It's used by the mail operation queue to notify the observers
2086 * attached to that signal that the operation finished. We need to use
2087 * that because tinymail does not give us the progress of a given
2088 * operation when it finishes (it directly calls the operation
2092 modest_mail_operation_notify_end (ModestMailOperation *self)
2094 ModestMailOperationState *state;
2096 /* Notify the observers about the mail opertation end */
2097 state = modest_mail_operation_clone_state (self);
2098 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2099 g_slice_free (ModestMailOperationState, state);