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 tny_folder_remove_msg (folder, header, NULL);
603 g_object_unref (header);
606 tny_folder_add_msg (folder, msg, &(priv->error));
612 g_object_unref (G_OBJECT(msg));
614 g_object_unref (G_OBJECT(folder));
616 modest_mail_operation_notify_end (self);
621 ModestMailOperation *mail_op;
622 TnyStoreAccount *account;
623 TnyTransportAccount *transport_account;
626 gchar *retrieve_type;
629 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
630 /* We use this folder observer to track the headers that have been
631 * added to a folder */
634 TnyList *new_headers;
635 } InternalFolderObserver;
639 } InternalFolderObserverClass;
641 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
643 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
644 internal_folder_observer,
646 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
650 foreach_add_item (gpointer header, gpointer user_data)
652 /* printf("DEBUG: %s: header subject=%s\n",
653 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
655 tny_list_prepend (TNY_LIST (user_data),
656 g_object_ref (G_OBJECT (header)));
659 /* This is the method that looks for new messages in a folder */
661 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
663 InternalFolderObserver *derived = (InternalFolderObserver *)self;
665 TnyFolderChangeChanged changed;
667 changed = tny_folder_change_get_changed (change);
669 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
672 /* Get added headers */
673 list = tny_simple_list_new ();
674 tny_folder_change_get_added_headers (change, list);
676 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
677 * __FUNCTION__, tny_list_get_length(list));
680 /* Add them to the folder observer */
681 tny_list_foreach (list, foreach_add_item,
682 derived->new_headers);
684 g_object_unref (G_OBJECT (list));
689 internal_folder_observer_init (InternalFolderObserver *self)
691 self->new_headers = tny_simple_list_new ();
694 internal_folder_observer_finalize (GObject *object)
696 InternalFolderObserver *self;
698 self = (InternalFolderObserver *) object;
699 g_object_unref (self->new_headers);
701 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
704 tny_folder_observer_init (TnyFolderObserverIface *iface)
706 iface->update_func = internal_folder_observer_update;
709 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
711 GObjectClass *object_class;
713 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
714 object_class = (GObjectClass*) klass;
715 object_class->finalize = internal_folder_observer_finalize;
721 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
724 TnyList *folders = tny_simple_list_new ();
726 tny_folder_store_get_folders (store, folders, query, NULL);
727 iter = tny_list_create_iterator (folders);
729 while (!tny_iterator_is_done (iter)) {
731 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
733 tny_list_prepend (all_folders, G_OBJECT (folder));
734 recurse_folders (folder, query, all_folders);
735 g_object_unref (G_OBJECT (folder));
737 tny_iterator_next (iter);
739 g_object_unref (G_OBJECT (iter));
740 g_object_unref (G_OBJECT (folders));
744 * Issues the "progress-changed" signal. The timer won't be removed,
745 * so you must call g_source_remove to stop the signal emission
748 idle_notify_progress (gpointer data)
750 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
751 ModestMailOperationState *state;
753 state = modest_mail_operation_clone_state (mail_op);
754 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
755 g_slice_free (ModestMailOperationState, state);
761 * Issues the "progress-changed" signal and removes the timer. It uses
762 * a lock to ensure that the progress information of the mail
763 * operation is not modified while there are notifications pending
766 idle_notify_progress_once (gpointer data)
770 pair = (ModestPair *) data;
772 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
774 /* Free the state and the reference to the mail operation */
775 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
776 g_object_unref (pair->first);
782 * Used by update_account_thread to notify the queue from the main
783 * loop. We call it inside an idle call to achieve that
786 notify_update_account_queue (gpointer data)
788 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
789 ModestMailOperationPrivate *priv = NULL;
791 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
793 modest_mail_operation_notify_end (mail_op);
794 g_object_unref (mail_op);
800 compare_headers_by_date (gconstpointer a,
803 TnyHeader **header1, **header2;
806 header1 = (TnyHeader **) a;
807 header2 = (TnyHeader **) b;
809 sent1 = tny_header_get_date_sent (*header1);
810 sent2 = tny_header_get_date_sent (*header2);
812 /* We want the most recent ones (greater time_t) at the
821 set_last_updated_idle (gpointer data)
823 /* It does not matter if the time is not exactly the same than
824 the time when this idle was called, it's just an
825 approximation and it won't be very different */
826 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
828 MODEST_ACCOUNT_LAST_UPDATED,
836 update_account_thread (gpointer thr_user_data)
838 UpdateAccountInfo *info;
839 TnyList *all_folders = NULL;
840 GPtrArray *new_headers;
841 TnyIterator *iter = NULL;
842 TnyFolderStoreQuery *query = NULL;
843 ModestMailOperationPrivate *priv;
844 ModestTnySendQueue *send_queue;
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, g_object_ref (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->user_data = user_data;
1448 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1450 g_object_unref (G_OBJECT (folder));
1452 /* Set status failed and set an error */
1453 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1454 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1455 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1456 _("Error trying to get a message. No folder found for header"));
1458 /* Notify the queue */
1459 modest_mail_operation_notify_end (self);
1464 get_msg_cb (TnyFolder *folder,
1470 GetMsgAsyncHelper *helper = NULL;
1471 ModestMailOperation *self = NULL;
1472 ModestMailOperationPrivate *priv = NULL;
1474 helper = (GetMsgAsyncHelper *) user_data;
1475 g_return_if_fail (helper != NULL);
1476 self = helper->mail_op;
1477 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1478 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1480 /* Check errors and cancel */
1482 priv->error = g_error_copy (*error);
1483 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1487 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1488 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1489 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1490 _("Error trying to refresh the contents of %s"),
1491 tny_folder_get_name (folder));
1495 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1497 /* If user defined callback function was defined, call it */
1498 if (helper->user_callback) {
1499 helper->user_callback (self, NULL, msg, helper->user_data);
1504 g_slice_free (GetMsgAsyncHelper, helper);
1506 /* Notify about operation end */
1507 modest_mail_operation_notify_end (self);
1511 get_msg_status_cb (GObject *obj,
1515 GetMsgAsyncHelper *helper = NULL;
1516 ModestMailOperation *self;
1517 ModestMailOperationPrivate *priv;
1518 ModestMailOperationState *state;
1520 g_return_if_fail (status != NULL);
1521 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1523 helper = (GetMsgAsyncHelper *) user_data;
1524 g_return_if_fail (helper != NULL);
1526 self = helper->mail_op;
1527 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1529 if ((status->position == 1) && (status->of_total == 100))
1535 state = modest_mail_operation_clone_state (self);
1536 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1537 g_slice_free (ModestMailOperationState, state);
1540 /****************************************************/
1542 ModestMailOperation *mail_op;
1544 GetMsgAsyncUserCallback user_callback;
1546 GDestroyNotify notify;
1550 GetMsgAsyncUserCallback user_callback;
1554 ModestMailOperation *mail_op;
1555 } NotifyGetMsgsInfo;
1559 * Used by get_msgs_full_thread to call the user_callback for each
1560 * message that has been read
1563 notify_get_msgs_full (gpointer data)
1565 NotifyGetMsgsInfo *info;
1567 info = (NotifyGetMsgsInfo *) data;
1569 /* Call the user callback */
1570 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1572 g_slice_free (NotifyGetMsgsInfo, info);
1578 * Used by get_msgs_full_thread to free al the thread resources and to
1579 * call the destroy function for the passed user_data
1582 get_msgs_full_destroyer (gpointer data)
1584 GetFullMsgsInfo *info;
1586 info = (GetFullMsgsInfo *) data;
1589 info->notify (info->user_data);
1592 g_object_unref (info->headers);
1593 g_slice_free (GetFullMsgsInfo, info);
1599 get_msgs_full_thread (gpointer thr_user_data)
1601 GetFullMsgsInfo *info;
1602 ModestMailOperationPrivate *priv = NULL;
1603 TnyIterator *iter = NULL;
1605 info = (GetFullMsgsInfo *) thr_user_data;
1606 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1608 iter = tny_list_create_iterator (info->headers);
1609 while (!tny_iterator_is_done (iter)) {
1613 header = TNY_HEADER (tny_iterator_get_current (iter));
1614 folder = tny_header_get_folder (header);
1616 /* Get message from folder */
1619 /* The callback will call it per each header */
1620 msg = tny_folder_get_msg (folder, header, &(priv->error));
1623 ModestMailOperationState *state;
1628 /* notify progress */
1629 state = modest_mail_operation_clone_state (info->mail_op);
1630 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1631 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1632 pair, (GDestroyNotify) modest_pair_free);
1634 /* The callback is the responsible for
1635 freeing the message */
1636 if (info->user_callback) {
1637 NotifyGetMsgsInfo *info_notify;
1638 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1639 info_notify->user_callback = info->user_callback;
1640 info_notify->mail_op = info->mail_op;
1641 info_notify->header = g_object_ref (header);
1642 info_notify->msg = g_object_ref (msg);
1643 info_notify->user_data = info->user_data;
1644 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1645 notify_get_msgs_full,
1648 g_object_unref (msg);
1651 /* Set status failed and set an error */
1652 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1653 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1654 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1655 "Error trying to get a message. No folder found for header");
1657 g_object_unref (header);
1658 tny_iterator_next (iter);
1661 /* Set operation status */
1662 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1663 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1665 /* Notify about operation end */
1666 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1668 /* Free thread resources. Will be called after all previous idles */
1669 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1675 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1676 TnyList *header_list,
1677 GetMsgAsyncUserCallback user_callback,
1679 GDestroyNotify notify)
1681 TnyHeader *header = NULL;
1682 TnyFolder *folder = NULL;
1684 ModestMailOperationPrivate *priv = NULL;
1685 GetFullMsgsInfo *info = NULL;
1686 gboolean size_ok = TRUE;
1688 TnyIterator *iter = NULL;
1690 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1692 /* Init mail operation */
1693 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1694 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1696 priv->total = tny_list_get_length(header_list);
1698 /* Get account and set it into mail_operation */
1699 if (tny_list_get_length (header_list) >= 1) {
1700 iter = tny_list_create_iterator (header_list);
1701 header = TNY_HEADER (tny_iterator_get_current (iter));
1702 folder = tny_header_get_folder (header);
1703 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1704 g_object_unref (header);
1705 g_object_unref (folder);
1707 if (tny_list_get_length (header_list) == 1) {
1708 g_object_unref (iter);
1713 /* Get msg size limit */
1714 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1715 MODEST_CONF_MSG_SIZE_LIMIT,
1718 g_clear_error (&(priv->error));
1719 max_size = G_MAXINT;
1721 max_size = max_size * KB;
1724 /* Check message size limits. If there is only one message
1725 always retrieve it */
1727 while (!tny_iterator_is_done (iter) && size_ok) {
1728 header = TNY_HEADER (tny_iterator_get_current (iter));
1729 if (tny_header_get_message_size (header) >= max_size)
1731 g_object_unref (header);
1732 tny_iterator_next (iter);
1734 g_object_unref (iter);
1738 /* Create the info */
1739 info = g_slice_new0 (GetFullMsgsInfo);
1740 info->mail_op = self;
1741 info->user_callback = user_callback;
1742 info->user_data = user_data;
1743 info->headers = g_object_ref (header_list);
1744 info->notify = notify;
1746 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1748 /* Set status failed and set an error */
1749 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1750 /* FIXME: the error msg is different for pop */
1751 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1752 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1753 _("emev_ni_ui_imap_msg_size_exceed_error"));
1754 /* Remove from queue and free resources */
1755 modest_mail_operation_notify_end (self);
1763 modest_mail_operation_remove_msg (ModestMailOperation *self,
1765 gboolean remove_to_trash)
1768 ModestMailOperationPrivate *priv;
1770 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1771 g_return_if_fail (TNY_IS_HEADER (header));
1773 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1774 folder = tny_header_get_folder (header);
1776 /* Get account and set it into mail_operation */
1777 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1779 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1781 /* Delete or move to trash */
1782 if (remove_to_trash) {
1783 TnyFolder *trash_folder;
1784 TnyStoreAccount *store_account;
1786 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1787 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1788 TNY_FOLDER_TYPE_TRASH);
1793 headers = tny_simple_list_new ();
1794 tny_list_append (headers, G_OBJECT (header));
1795 g_object_unref (header);
1798 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1799 g_object_unref (headers);
1800 /* g_object_unref (trash_folder); */
1802 ModestMailOperationPrivate *priv;
1804 /* Set status failed and set an error */
1805 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1806 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1807 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1808 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1809 _("Error trying to delete a message. Trash folder not found"));
1812 g_object_unref (G_OBJECT (store_account));
1814 tny_folder_remove_msg (folder, header, &(priv->error));
1816 tny_folder_sync(folder, TRUE, &(priv->error));
1821 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1823 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1826 g_object_unref (G_OBJECT (folder));
1828 /* Notify about operation end */
1829 modest_mail_operation_notify_end (self);
1833 transfer_msgs_status_cb (GObject *obj,
1837 XFerMsgAsyncHelper *helper = NULL;
1838 ModestMailOperation *self;
1839 ModestMailOperationPrivate *priv;
1840 ModestMailOperationState *state;
1843 g_return_if_fail (status != NULL);
1844 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1846 helper = (XFerMsgAsyncHelper *) user_data;
1847 g_return_if_fail (helper != NULL);
1849 self = helper->mail_op;
1850 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1852 if ((status->position == 1) && (status->of_total == 100))
1855 priv->done = status->position;
1856 priv->total = status->of_total;
1858 state = modest_mail_operation_clone_state (self);
1859 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1860 g_slice_free (ModestMailOperationState, state);
1865 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1867 XFerMsgAsyncHelper *helper;
1868 ModestMailOperation *self;
1869 ModestMailOperationPrivate *priv;
1871 helper = (XFerMsgAsyncHelper *) user_data;
1872 self = helper->mail_op;
1874 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1877 priv->error = g_error_copy (*err);
1879 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1880 } else if (cancelled) {
1881 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1882 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1883 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1884 _("Error trying to refresh the contents of %s"),
1885 tny_folder_get_name (folder));
1888 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1891 /* If user defined callback function was defined, call it */
1892 if (helper->user_callback) {
1893 helper->user_callback (priv->source, helper->user_data);
1897 g_object_unref (helper->headers);
1898 g_object_unref (helper->dest_folder);
1899 g_object_unref (helper->mail_op);
1900 g_slice_free (XFerMsgAsyncHelper, helper);
1901 g_object_unref (folder);
1903 /* Notify about operation end */
1904 modest_mail_operation_notify_end (self);
1908 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1911 gboolean delete_original,
1912 XferMsgsAsynUserCallback user_callback,
1915 ModestMailOperationPrivate *priv;
1917 TnyFolder *src_folder;
1918 XFerMsgAsyncHelper *helper;
1920 ModestTnyFolderRules rules;
1922 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1923 g_return_if_fail (TNY_IS_LIST (headers));
1924 g_return_if_fail (TNY_IS_FOLDER (folder));
1926 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1929 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1931 /* Apply folder rules */
1932 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1934 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1935 /* Set status failed and set an error */
1936 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1937 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1938 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1939 _("FIXME: folder does not accept msgs"));
1940 /* Notify the queue */
1941 modest_mail_operation_notify_end (self);
1945 /* Create the helper */
1946 helper = g_slice_new0 (XFerMsgAsyncHelper);
1947 helper->mail_op = g_object_ref(self);
1948 helper->dest_folder = g_object_ref(folder);
1949 helper->headers = g_object_ref(headers);
1950 helper->user_callback = user_callback;
1951 helper->user_data = user_data;
1953 /* Get source folder */
1954 iter = tny_list_create_iterator (headers);
1955 header = TNY_HEADER (tny_iterator_get_current (iter));
1956 src_folder = tny_header_get_folder (header);
1957 g_object_unref (header);
1958 g_object_unref (iter);
1960 /* Get account and set it into mail_operation */
1961 priv->account = modest_tny_folder_get_account (src_folder);
1963 /* Transfer messages */
1964 tny_folder_transfer_msgs_async (src_folder,
1969 transfer_msgs_status_cb,
1975 on_refresh_folder (TnyFolder *folder,
1980 RefreshAsyncHelper *helper = NULL;
1981 ModestMailOperation *self = NULL;
1982 ModestMailOperationPrivate *priv = NULL;
1984 helper = (RefreshAsyncHelper *) user_data;
1985 self = helper->mail_op;
1986 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1989 priv->error = g_error_copy (*error);
1990 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1995 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1996 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1997 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1998 _("Error trying to refresh the contents of %s"),
1999 tny_folder_get_name (folder));
2003 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2006 /* Call user defined callback, if it exists */
2007 if (helper->user_callback)
2008 helper->user_callback (priv->source, folder, helper->user_data);
2011 g_object_unref (helper->mail_op);
2012 g_slice_free (RefreshAsyncHelper, helper);
2013 g_object_unref (folder);
2015 /* Notify about operation end */
2016 modest_mail_operation_notify_end (self);
2020 on_refresh_folder_status_update (GObject *obj,
2024 RefreshAsyncHelper *helper = NULL;
2025 ModestMailOperation *self = NULL;
2026 ModestMailOperationPrivate *priv = NULL;
2027 ModestMailOperationState *state;
2029 g_return_if_fail (user_data != NULL);
2030 g_return_if_fail (status != NULL);
2031 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2033 helper = (RefreshAsyncHelper *) user_data;
2034 self = helper->mail_op;
2035 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2037 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2039 priv->done = status->position;
2040 priv->total = status->of_total;
2042 state = modest_mail_operation_clone_state (self);
2043 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2044 g_slice_free (ModestMailOperationState, state);
2048 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2050 RefreshAsyncUserCallback user_callback,
2053 ModestMailOperationPrivate *priv = NULL;
2054 RefreshAsyncHelper *helper = NULL;
2056 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2058 /* Pick a reference */
2059 g_object_ref (folder);
2061 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2063 /* Get account and set it into mail_operation */
2064 priv->account = modest_tny_folder_get_account (folder);
2066 /* Create the helper */
2067 helper = g_slice_new0 (RefreshAsyncHelper);
2068 helper->mail_op = g_object_ref(self);
2069 helper->user_callback = user_callback;
2070 helper->user_data = user_data;
2072 /* Refresh the folder. TODO: tinymail could issue a status
2073 updates before the callback call then this could happen. We
2074 must review the design */
2075 tny_folder_refresh_async (folder,
2077 on_refresh_folder_status_update,
2083 * It's used by the mail operation queue to notify the observers
2084 * attached to that signal that the operation finished. We need to use
2085 * that because tinymail does not give us the progress of a given
2086 * operation when it finishes (it directly calls the operation
2090 modest_mail_operation_notify_end (ModestMailOperation *self)
2092 ModestMailOperationState *state;
2094 /* Notify the observers about the mail opertation end */
2095 state = modest_mail_operation_clone_state (self);
2096 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2097 g_slice_free (ModestMailOperationState, state);