1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-camel-pop-store-account.h>
38 #include <tny-simple-list.h>
39 #include <tny-send-queue.h>
40 #include <tny-status.h>
41 #include <tny-folder-observer.h>
42 #include <camel/camel-stream-mem.h>
43 #include <glib/gi18n.h>
44 #include "modest-platform.h"
45 #include <modest-tny-account.h>
46 #include <modest-tny-send-queue.h>
47 #include <modest-runtime.h>
48 #include "modest-text-utils.h"
49 #include "modest-tny-msg.h"
50 #include "modest-tny-folder.h"
51 #include "modest-tny-platform-factory.h"
52 #include "modest-marshal.h"
53 #include "modest-error.h"
54 #include "modest-mail-operation.h"
58 /* 'private'/'protected' functions */
59 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
60 static void modest_mail_operation_init (ModestMailOperation *obj);
61 static void modest_mail_operation_finalize (GObject *obj);
63 static void get_msg_cb (TnyFolder *folder,
69 static void get_msg_status_cb (GObject *obj,
73 static void modest_mail_operation_notify_end (ModestMailOperation *self);
75 static gboolean did_a_cancel = FALSE;
77 enum _ModestMailOperationSignals
79 PROGRESS_CHANGED_SIGNAL,
84 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
85 struct _ModestMailOperationPrivate {
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);
213 g_error_free (priv->error);
217 g_object_unref (priv->source);
221 g_object_unref (priv->account);
222 priv->account = NULL;
226 G_OBJECT_CLASS(parent_class)->finalize (obj);
230 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
233 ModestMailOperation *obj;
234 ModestMailOperationPrivate *priv;
236 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
237 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
239 priv->op_type = op_type;
241 priv->source = g_object_ref(source);
247 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
249 ErrorCheckingUserCallback error_handler,
252 ModestMailOperation *obj;
253 ModestMailOperationPrivate *priv;
255 obj = modest_mail_operation_new (op_type, source);
256 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
258 g_return_val_if_fail (error_handler != NULL, obj);
259 priv->error_checking = error_handler;
265 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
267 ModestMailOperationPrivate *priv;
269 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
270 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
272 if (priv->error_checking != NULL)
273 priv->error_checking (self, priv->error_checking_user_data);
277 ModestMailOperationTypeOperation
278 modest_mail_operation_get_type_operation (ModestMailOperation *self)
280 ModestMailOperationPrivate *priv;
282 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
284 return priv->op_type;
288 modest_mail_operation_is_mine (ModestMailOperation *self,
291 ModestMailOperationPrivate *priv;
293 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
294 if (priv->source == NULL) return FALSE;
296 return priv->source == me;
300 modest_mail_operation_get_source (ModestMailOperation *self)
302 ModestMailOperationPrivate *priv;
304 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
306 return g_object_ref (priv->source);
309 ModestMailOperationStatus
310 modest_mail_operation_get_status (ModestMailOperation *self)
312 ModestMailOperationPrivate *priv;
314 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
315 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
316 MODEST_MAIL_OPERATION_STATUS_INVALID);
318 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
323 modest_mail_operation_get_error (ModestMailOperation *self)
325 ModestMailOperationPrivate *priv;
327 g_return_val_if_fail (self, NULL);
328 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
330 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
335 modest_mail_operation_cancel (ModestMailOperation *self)
337 ModestMailOperationPrivate *priv;
339 if (!MODEST_IS_MAIL_OPERATION (self)) {
340 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
344 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
346 /* cancel current operation in account */
347 //tny_account_cancel (priv->account);
352 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
354 /* Notify about operation end */
355 modest_mail_operation_notify_end (self);
361 modest_mail_operation_get_task_done (ModestMailOperation *self)
363 ModestMailOperationPrivate *priv;
365 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
367 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
372 modest_mail_operation_get_task_total (ModestMailOperation *self)
374 ModestMailOperationPrivate *priv;
376 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
378 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
383 modest_mail_operation_is_finished (ModestMailOperation *self)
385 ModestMailOperationPrivate *priv;
386 gboolean retval = FALSE;
388 if (!MODEST_IS_MAIL_OPERATION (self)) {
389 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
393 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
395 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
396 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
397 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
398 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
408 modest_mail_operation_get_id (ModestMailOperation *self)
410 ModestMailOperationPrivate *priv;
412 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
414 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
419 modest_mail_operation_set_id (ModestMailOperation *self,
422 ModestMailOperationPrivate *priv;
424 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
426 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
431 * Creates an image of the current state of a mail operation, the
432 * caller must free it
434 static ModestMailOperationState *
435 modest_mail_operation_clone_state (ModestMailOperation *self)
437 ModestMailOperationState *state;
438 ModestMailOperationPrivate *priv;
440 /* FIXME: this should be fixed properly
442 * in some cases, priv was NULL, so checking here to
445 g_return_val_if_fail (self, NULL);
446 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
447 g_return_val_if_fail (priv, NULL);
452 state = g_slice_new (ModestMailOperationState);
454 state->status = priv->status;
455 state->op_type = priv->op_type;
456 state->done = priv->done;
457 state->total = priv->total;
458 state->finished = modest_mail_operation_is_finished (self);
463 /* ******************************************************************* */
464 /* ************************** SEND ACTIONS ************************* */
465 /* ******************************************************************* */
468 modest_mail_operation_send_mail (ModestMailOperation *self,
469 TnyTransportAccount *transport_account,
472 TnySendQueue *send_queue = NULL;
473 ModestMailOperationPrivate *priv;
475 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
476 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
477 g_return_if_fail (TNY_IS_MSG (msg));
479 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
481 /* Get account and set it into mail_operation */
482 priv->account = g_object_ref (transport_account);
484 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
485 if (!TNY_IS_SEND_QUEUE(send_queue)) {
486 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
487 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
488 "modest: could not find send queue for account\n");
490 tny_send_queue_add (send_queue, msg, &(priv->error));
493 /* Notify about operation end */
494 modest_mail_operation_notify_end (self);
498 modest_mail_operation_send_new_mail (ModestMailOperation *self,
499 TnyTransportAccount *transport_account,
501 const gchar *from, const gchar *to,
502 const gchar *cc, const gchar *bcc,
503 const gchar *subject, const gchar *plain_body,
504 const gchar *html_body,
505 const GList *attachments_list,
506 TnyHeaderFlags priority_flags)
508 TnyMsg *new_msg = NULL;
509 TnyFolder *folder = NULL;
510 TnyHeader *header = NULL;
511 ModestMailOperationPrivate *priv = NULL;
513 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
514 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
516 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
518 /* Get account and set it into mail_operation */
519 priv->account = g_object_ref (transport_account);
521 /* Check parametters */
523 /* Set status failed and set an error */
524 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
525 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
526 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
527 _("Error trying to send a mail. You need to set at least one recipient"));
531 if (html_body == NULL) {
532 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
534 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
537 g_printerr ("modest: failed to create a new msg\n");
541 /* Set priority flags in message */
542 header = tny_msg_get_header (new_msg);
543 if (priority_flags != 0)
544 tny_header_set_flags (header, priority_flags);
546 /* Call mail operation */
547 modest_mail_operation_send_mail (self, transport_account, new_msg);
549 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
551 if (draft_msg != NULL) {
552 header = tny_msg_get_header (draft_msg);
553 /* Note: This can fail (with a warning) if the message is not really already in a folder,
554 * because this function requires it to have a UID. */
555 tny_folder_remove_msg (folder, header, NULL);
556 g_object_unref (header);
561 g_object_unref (G_OBJECT (new_msg));
565 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
566 TnyTransportAccount *transport_account,
568 const gchar *from, const gchar *to,
569 const gchar *cc, const gchar *bcc,
570 const gchar *subject, const gchar *plain_body,
571 const gchar *html_body,
572 const GList *attachments_list,
573 TnyHeaderFlags priority_flags)
576 TnyFolder *folder = NULL;
577 TnyHeader *header = NULL;
578 ModestMailOperationPrivate *priv = NULL;
580 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
581 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
583 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
585 /* Get account and set it into mail_operation */
586 priv->account = g_object_ref (transport_account);
588 if (html_body == NULL) {
589 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
591 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
594 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
595 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
596 "modest: failed to create a new msg\n");
600 /* add priority flags */
601 header = tny_msg_get_header (msg);
602 tny_header_set_flags (header, priority_flags);
604 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
606 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
607 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
608 "modest: failed to create a new msg\n");
612 if (draft_msg != NULL) {
613 header = tny_msg_get_header (draft_msg);
614 /* Remove the old draft expunging it */
615 tny_folder_remove_msg (folder, header, NULL);
616 tny_folder_sync (folder, TRUE, NULL);
617 g_object_unref (header);
620 tny_folder_add_msg (folder, msg, &(priv->error));
626 g_object_unref (G_OBJECT(msg));
628 g_object_unref (G_OBJECT(folder));
630 modest_mail_operation_notify_end (self);
635 ModestMailOperation *mail_op;
636 TnyStoreAccount *account;
637 TnyTransportAccount *transport_account;
640 gchar *retrieve_type;
644 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
645 /* We use this folder observer to track the headers that have been
646 * added to a folder */
649 TnyList *new_headers;
650 } InternalFolderObserver;
654 } InternalFolderObserverClass;
656 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
658 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
659 internal_folder_observer,
661 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
665 foreach_add_item (gpointer header, gpointer user_data)
667 /* printf("DEBUG: %s: header subject=%s\n",
668 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
670 tny_list_prepend (TNY_LIST (user_data),
671 g_object_ref (G_OBJECT (header)));
674 /* This is the method that looks for new messages in a folder */
676 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
678 InternalFolderObserver *derived = (InternalFolderObserver *)self;
680 TnyFolderChangeChanged changed;
682 changed = tny_folder_change_get_changed (change);
684 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
687 /* Get added headers */
688 list = tny_simple_list_new ();
689 tny_folder_change_get_added_headers (change, list);
691 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
692 * __FUNCTION__, tny_list_get_length(list));
695 /* Add them to the folder observer */
696 tny_list_foreach (list, foreach_add_item,
697 derived->new_headers);
699 g_object_unref (G_OBJECT (list));
704 internal_folder_observer_init (InternalFolderObserver *self)
706 self->new_headers = tny_simple_list_new ();
709 internal_folder_observer_finalize (GObject *object)
711 InternalFolderObserver *self;
713 self = (InternalFolderObserver *) object;
714 g_object_unref (self->new_headers);
716 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
719 tny_folder_observer_init (TnyFolderObserverIface *iface)
721 iface->update_func = internal_folder_observer_update;
724 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
726 GObjectClass *object_class;
728 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
729 object_class = (GObjectClass*) klass;
730 object_class->finalize = internal_folder_observer_finalize;
736 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
739 TnyList *folders = tny_simple_list_new ();
741 tny_folder_store_get_folders (store, folders, query, NULL);
742 iter = tny_list_create_iterator (folders);
744 while (!tny_iterator_is_done (iter)) {
746 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
748 tny_list_prepend (all_folders, G_OBJECT (folder));
749 recurse_folders (folder, query, all_folders);
750 g_object_unref (G_OBJECT (folder));
752 tny_iterator_next (iter);
754 g_object_unref (G_OBJECT (iter));
755 g_object_unref (G_OBJECT (folders));
759 * Issues the "progress-changed" signal. The timer won't be removed,
760 * so you must call g_source_remove to stop the signal emission
763 idle_notify_progress (gpointer data)
765 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
766 ModestMailOperationState *state;
768 state = modest_mail_operation_clone_state (mail_op);
769 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
770 g_slice_free (ModestMailOperationState, state);
776 * Issues the "progress-changed" signal and removes the timer. It uses
777 * a lock to ensure that the progress information of the mail
778 * operation is not modified while there are notifications pending
781 idle_notify_progress_once (gpointer data)
785 pair = (ModestPair *) data;
787 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
789 /* Free the state and the reference to the mail operation */
790 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
791 g_object_unref (pair->first);
797 * Used by update_account_thread to notify the queue from the main
798 * loop. We call it inside an idle call to achieve that
801 notify_update_account_queue (gpointer data)
803 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
804 ModestMailOperationPrivate *priv = NULL;
806 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
808 modest_mail_operation_notify_end (mail_op);
809 g_object_unref (mail_op);
815 compare_headers_by_date (gconstpointer a,
818 TnyHeader **header1, **header2;
821 header1 = (TnyHeader **) a;
822 header2 = (TnyHeader **) b;
824 sent1 = tny_header_get_date_sent (*header1);
825 sent2 = tny_header_get_date_sent (*header2);
827 /* We want the most recent ones (greater time_t) at the
836 set_last_updated_idle (gpointer data)
838 /* It does not matter if the time is not exactly the same than
839 the time when this idle was called, it's just an
840 approximation and it won't be very different */
841 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
843 MODEST_ACCOUNT_LAST_UPDATED,
851 update_account_thread (gpointer thr_user_data)
853 UpdateAccountInfo *info;
854 TnyList *all_folders = NULL;
855 GPtrArray *new_headers;
856 TnyIterator *iter = NULL;
857 TnyFolderStoreQuery *query = NULL;
858 ModestMailOperationPrivate *priv;
859 ModestTnySendQueue *send_queue;
861 info = (UpdateAccountInfo *) thr_user_data;
862 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
864 /* Get account and set it into mail_operation */
865 priv->account = g_object_ref (info->account);
868 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
869 * show any updates unless we do that
871 if (TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
872 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
874 /* Get all the folders. We can do it synchronously because
875 we're already running in a different thread than the UI */
876 all_folders = tny_simple_list_new ();
877 query = tny_folder_store_query_new ();
878 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
879 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
884 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
888 iter = tny_list_create_iterator (all_folders);
889 while (!tny_iterator_is_done (iter)) {
890 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
892 recurse_folders (folder, query, all_folders);
893 tny_iterator_next (iter);
895 g_object_unref (G_OBJECT (iter));
897 /* Update status and notify. We need to call the notification
898 with a source function in order to call it from the main
899 loop. We need that in order not to get into trouble with
900 Gtk+. We use a timeout in order to provide more status
901 information, because the sync tinymail call does not
902 provide it for the moment */
903 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
905 /* Refresh folders */
906 new_headers = g_ptr_array_new ();
907 iter = tny_list_create_iterator (all_folders);
909 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
911 InternalFolderObserver *observer;
912 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
914 /* Refresh the folder */
915 /* Our observer receives notification of new emails during folder refreshes,
916 * so we can use observer->new_headers.
917 * TODO: This does not seem to be providing accurate numbers.
918 * Possibly the observer is notified asynchronously.
920 observer = g_object_new (internal_folder_observer_get_type (), NULL);
921 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
923 /* This gets the status information (headers) from the server.
924 * We use the blocking version, because we are already in a separate
928 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
929 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
932 /* If the retrieve type is full messages, refresh and get the messages */
933 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
935 iter = tny_list_create_iterator (observer->new_headers);
936 while (!tny_iterator_is_done (iter)) {
937 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
938 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
939 * __FUNCTION__, tny_account_get_id (priv->account),
940 * tny_header_get_subject (header));
943 /* Apply per-message size limits */
944 if (tny_header_get_message_size (header) < info->max_size)
945 g_ptr_array_add (new_headers, g_object_ref (header));
947 g_object_unref (header);
948 tny_iterator_next (iter);
950 g_object_unref (iter);
953 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
954 g_object_unref (observer);
958 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
960 g_object_unref (G_OBJECT (folder));
961 tny_iterator_next (iter);
964 did_a_cancel = FALSE;
966 g_object_unref (G_OBJECT (iter));
967 g_source_remove (timeout);
969 if (new_headers->len > 0) {
973 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
975 /* Apply message count limit */
976 /* If the number of messages exceeds the maximum, ask the
977 * user to download them all,
978 * as per the UI spec "Retrieval Limits" section in 4.4:
980 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
981 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
982 if (new_headers->len > info->retrieve_limit) {
983 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
984 * with 'Get all' and 'Newest only' buttons. */
985 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
986 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
987 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
988 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
989 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
994 priv->total = MIN (new_headers->len, info->retrieve_limit);
995 while (msg_num < priv->total) {
997 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
998 TnyFolder *folder = tny_header_get_folder (header);
999 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1000 ModestMailOperationState *state;
1004 /* We can not just use the mail operation because the
1005 values of done and total could change before the
1007 state = modest_mail_operation_clone_state (info->mail_op);
1008 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1009 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1010 pair, (GDestroyNotify) modest_pair_free);
1012 g_object_unref (msg);
1013 g_object_unref (folder);
1017 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1018 g_ptr_array_free (new_headers, FALSE);
1022 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1025 if (priv->account != NULL)
1026 g_object_unref (priv->account);
1027 priv->account = g_object_ref (info->transport_account);
1029 send_queue = modest_runtime_get_send_queue (info->transport_account);
1031 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
1032 modest_tny_send_queue_try_to_send (send_queue);
1033 g_source_remove (timeout);
1035 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1036 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1037 "cannot create a send queue for %s\n",
1038 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1039 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1042 /* Check if the operation was a success */
1044 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1046 /* Update the last updated key */
1047 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1048 set_last_updated_idle,
1049 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1050 (GDestroyNotify) g_free);
1054 /* Notify about operation end. Note that the info could be
1055 freed before this idle happens, but the mail operation will
1057 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1060 g_object_unref (query);
1061 g_object_unref (all_folders);
1062 g_object_unref (info->account);
1063 g_object_unref (info->transport_account);
1064 g_free (info->retrieve_type);
1065 g_slice_free (UpdateAccountInfo, info);
1071 modest_mail_operation_update_account (ModestMailOperation *self,
1072 const gchar *account_name)
1075 UpdateAccountInfo *info;
1076 ModestMailOperationPrivate *priv;
1077 ModestAccountMgr *mgr;
1078 TnyStoreAccount *modest_account;
1079 TnyTransportAccount *transport_account;
1081 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1082 g_return_val_if_fail (account_name, FALSE);
1084 /* Make sure that we have a connection, and request one
1086 * TODO: Is there some way to trigger this for every attempt to
1087 * use the network? */
1088 if (!modest_platform_connect_and_wait(NULL))
1091 /* Init mail operation. Set total and done to 0, and do not
1092 update them, this way the progress objects will know that
1093 we have no clue about the number of the objects */
1094 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1097 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1099 /* Get the Modest account */
1100 modest_account = (TnyStoreAccount *)
1101 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1103 TNY_ACCOUNT_TYPE_STORE);
1105 if (!modest_account) {
1106 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1107 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1108 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1109 "cannot get tny store account for %s\n", account_name);
1110 modest_mail_operation_notify_end (self);
1116 /* Get the transport account, we can not do it in the thread
1117 due to some problems with dbus */
1118 transport_account = (TnyTransportAccount *)
1119 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1121 if (!transport_account) {
1122 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1123 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1124 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1125 "cannot get tny transport account for %s\n", account_name);
1126 modest_mail_operation_notify_end (self);
1131 /* Create the helper object */
1132 info = g_slice_new (UpdateAccountInfo);
1133 info->mail_op = self;
1134 info->account = modest_account;
1135 info->transport_account = transport_account;
1137 /* Get the message size limit */
1138 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1139 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1140 if (info->max_size == 0)
1141 info->max_size = G_MAXINT;
1143 info->max_size = info->max_size * KB;
1145 /* Get per-account retrieval type */
1146 mgr = modest_runtime_get_account_mgr ();
1147 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1148 MODEST_ACCOUNT_RETRIEVE, FALSE);
1150 /* Get per-account message amount retrieval limit */
1151 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1152 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1153 if (info->retrieve_limit == 0)
1154 info->retrieve_limit = G_MAXINT;
1156 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1158 /* Set account busy */
1159 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1160 priv->account_name = g_strdup(account_name);
1162 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1167 /* ******************************************************************* */
1168 /* ************************** STORE ACTIONS ************************* */
1169 /* ******************************************************************* */
1173 modest_mail_operation_create_folder (ModestMailOperation *self,
1174 TnyFolderStore *parent,
1177 ModestMailOperationPrivate *priv;
1178 TnyFolder *new_folder = NULL;
1180 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1181 g_return_val_if_fail (name, NULL);
1183 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1186 if (TNY_IS_FOLDER (parent)) {
1187 /* Check folder rules */
1188 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1189 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1190 /* Set status failed and set an error */
1191 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1192 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1193 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1194 _("mail_in_ui_folder_create_error"));
1199 /* Create the folder */
1200 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1201 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1203 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1206 /* Notify about operation end */
1207 modest_mail_operation_notify_end (self);
1213 modest_mail_operation_remove_folder (ModestMailOperation *self,
1215 gboolean remove_to_trash)
1217 TnyAccount *account;
1218 ModestMailOperationPrivate *priv;
1219 ModestTnyFolderRules rules;
1221 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1222 g_return_if_fail (TNY_IS_FOLDER (folder));
1224 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1226 /* Check folder rules */
1227 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1228 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1229 /* Set status failed and set an error */
1230 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1231 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1232 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1233 _("mail_in_ui_folder_delete_error"));
1237 /* Get the account */
1238 account = modest_tny_folder_get_account (folder);
1239 priv->account = g_object_ref(account);
1241 /* Delete folder or move to trash */
1242 if (remove_to_trash) {
1243 TnyFolder *trash_folder = NULL;
1244 trash_folder = modest_tny_account_get_special_folder (account,
1245 TNY_FOLDER_TYPE_TRASH);
1246 /* TODO: error_handling */
1247 modest_mail_operation_xfer_folder (self, folder,
1248 TNY_FOLDER_STORE (trash_folder), TRUE);
1250 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1252 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1253 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1256 g_object_unref (G_OBJECT (parent));
1258 g_object_unref (G_OBJECT (account));
1261 /* Notify about operation end */
1262 modest_mail_operation_notify_end (self);
1266 transfer_folder_status_cb (GObject *obj,
1270 ModestMailOperation *self;
1271 ModestMailOperationPrivate *priv;
1272 ModestMailOperationState *state;
1274 g_return_if_fail (status != NULL);
1275 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1277 self = MODEST_MAIL_OPERATION (user_data);
1278 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1280 if ((status->position == 1) && (status->of_total == 100))
1283 priv->done = status->position;
1284 priv->total = status->of_total;
1286 state = modest_mail_operation_clone_state (self);
1287 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1288 g_slice_free (ModestMailOperationState, state);
1293 transfer_folder_cb (TnyFolder *folder,
1294 TnyFolderStore *into,
1296 TnyFolder *new_folder, GError **err,
1299 ModestMailOperation *self = NULL;
1300 ModestMailOperationPrivate *priv = NULL;
1302 self = MODEST_MAIL_OPERATION (user_data);
1304 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1307 priv->error = g_error_copy (*err);
1309 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1310 } else if (cancelled) {
1311 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1312 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1313 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1314 _("Transference of %s was cancelled."),
1315 tny_folder_get_name (folder));
1318 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1322 g_object_unref (folder);
1323 g_object_unref (into);
1324 if (new_folder != NULL)
1325 g_object_unref (new_folder);
1327 /* Notify about operation end */
1328 modest_mail_operation_notify_end (self);
1332 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1334 TnyFolderStore *parent,
1335 gboolean delete_original)
1337 ModestMailOperationPrivate *priv = NULL;
1338 ModestTnyFolderRules parent_rules, rules;
1340 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1341 g_return_if_fail (TNY_IS_FOLDER (folder));
1342 g_return_if_fail (TNY_IS_FOLDER (parent));
1344 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1346 /* Get account and set it into mail_operation */
1347 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1348 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1350 /* Get folder rules */
1351 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1352 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1354 if (!TNY_IS_FOLDER_STORE (parent)) {
1358 /* The moveable restriction is applied also to copy operation */
1359 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1360 /* Set status failed and set an error */
1361 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1362 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1363 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1364 _("mail_in_ui_folder_move_target_error"));
1366 /* Notify the queue */
1367 modest_mail_operation_notify_end (self);
1368 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1369 /* Set status failed and set an error */
1370 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1371 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1372 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1373 _("FIXME: parent folder does not accept new folders"));
1375 /* Notify the queue */
1376 modest_mail_operation_notify_end (self);
1378 /* Pick references for async calls */
1379 g_object_ref (folder);
1380 g_object_ref (parent);
1382 /* Move/Copy folder */
1383 tny_folder_copy_async (folder,
1385 tny_folder_get_name (folder),
1388 transfer_folder_status_cb,
1394 modest_mail_operation_rename_folder (ModestMailOperation *self,
1398 ModestMailOperationPrivate *priv;
1399 ModestTnyFolderRules rules;
1401 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1402 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1403 g_return_if_fail (name);
1405 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1407 /* Get account and set it into mail_operation */
1408 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1410 /* Check folder rules */
1411 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1412 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1413 /* Set status failed and set an error */
1414 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1415 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1416 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1417 _("FIXME: unable to rename"));
1419 /* Notify about operation end */
1420 modest_mail_operation_notify_end (self);
1422 /* Rename. Camel handles folder subscription/unsubscription */
1423 TnyFolderStore *into;
1425 into = tny_folder_get_folder_store (folder);
1426 tny_folder_copy_async (folder, into, name, TRUE,
1428 transfer_folder_status_cb,
1431 g_object_unref (into);
1436 /* ******************************************************************* */
1437 /* ************************** MSG ACTIONS ************************* */
1438 /* ******************************************************************* */
1440 void modest_mail_operation_get_msg (ModestMailOperation *self,
1442 GetMsgAsyncUserCallback user_callback,
1445 GetMsgAsyncHelper *helper = NULL;
1447 ModestMailOperationPrivate *priv;
1449 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1450 g_return_if_fail (TNY_IS_HEADER (header));
1452 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1453 folder = tny_header_get_folder (header);
1455 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1457 /* Get message from folder */
1459 /* Get account and set it into mail_operation */
1460 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1462 helper = g_slice_new0 (GetMsgAsyncHelper);
1463 helper->mail_op = self;
1464 helper->user_callback = user_callback;
1465 helper->user_data = user_data;
1467 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1469 g_object_unref (G_OBJECT (folder));
1471 /* Set status failed and set an error */
1472 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1473 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1474 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1475 _("Error trying to get a message. No folder found for header"));
1477 /* Notify the queue */
1478 modest_mail_operation_notify_end (self);
1483 get_msg_cb (TnyFolder *folder,
1489 GetMsgAsyncHelper *helper = NULL;
1490 ModestMailOperation *self = NULL;
1491 ModestMailOperationPrivate *priv = NULL;
1493 helper = (GetMsgAsyncHelper *) user_data;
1494 g_return_if_fail (helper != NULL);
1495 self = helper->mail_op;
1496 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1497 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1499 /* Check errors and cancel */
1501 priv->error = g_error_copy (*error);
1502 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1506 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1507 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1508 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1509 _("Error trying to refresh the contents of %s"),
1510 tny_folder_get_name (folder));
1514 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1516 /* If user defined callback function was defined, call it */
1517 if (helper->user_callback) {
1518 helper->user_callback (self, NULL, msg, helper->user_data);
1523 g_slice_free (GetMsgAsyncHelper, helper);
1525 /* Notify about operation end */
1526 modest_mail_operation_notify_end (self);
1530 get_msg_status_cb (GObject *obj,
1534 GetMsgAsyncHelper *helper = NULL;
1535 ModestMailOperation *self;
1536 ModestMailOperationPrivate *priv;
1537 ModestMailOperationState *state;
1539 g_return_if_fail (status != NULL);
1540 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1542 helper = (GetMsgAsyncHelper *) user_data;
1543 g_return_if_fail (helper != NULL);
1545 self = helper->mail_op;
1546 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1548 if ((status->position == 1) && (status->of_total == 100))
1554 state = modest_mail_operation_clone_state (self);
1555 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1556 g_slice_free (ModestMailOperationState, state);
1559 /****************************************************/
1561 ModestMailOperation *mail_op;
1563 GetMsgAsyncUserCallback user_callback;
1565 GDestroyNotify notify;
1569 GetMsgAsyncUserCallback user_callback;
1573 ModestMailOperation *mail_op;
1574 } NotifyGetMsgsInfo;
1578 * Used by get_msgs_full_thread to call the user_callback for each
1579 * message that has been read
1582 notify_get_msgs_full (gpointer data)
1584 NotifyGetMsgsInfo *info;
1586 info = (NotifyGetMsgsInfo *) data;
1588 /* Call the user callback */
1589 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1591 g_slice_free (NotifyGetMsgsInfo, info);
1597 * Used by get_msgs_full_thread to free al the thread resources and to
1598 * call the destroy function for the passed user_data
1601 get_msgs_full_destroyer (gpointer data)
1603 GetFullMsgsInfo *info;
1605 info = (GetFullMsgsInfo *) data;
1608 info->notify (info->user_data);
1611 g_object_unref (info->headers);
1612 g_slice_free (GetFullMsgsInfo, info);
1618 get_msgs_full_thread (gpointer thr_user_data)
1620 GetFullMsgsInfo *info;
1621 ModestMailOperationPrivate *priv = NULL;
1622 TnyIterator *iter = NULL;
1624 info = (GetFullMsgsInfo *) thr_user_data;
1625 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1627 iter = tny_list_create_iterator (info->headers);
1628 while (!tny_iterator_is_done (iter)) {
1632 header = TNY_HEADER (tny_iterator_get_current (iter));
1633 folder = tny_header_get_folder (header);
1635 /* Get message from folder */
1638 /* The callback will call it per each header */
1639 msg = tny_folder_get_msg (folder, header, &(priv->error));
1642 ModestMailOperationState *state;
1647 /* notify progress */
1648 state = modest_mail_operation_clone_state (info->mail_op);
1649 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1650 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1651 pair, (GDestroyNotify) modest_pair_free);
1653 /* The callback is the responsible for
1654 freeing the message */
1655 if (info->user_callback) {
1656 NotifyGetMsgsInfo *info_notify;
1657 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1658 info_notify->user_callback = info->user_callback;
1659 info_notify->mail_op = info->mail_op;
1660 info_notify->header = g_object_ref (header);
1661 info_notify->msg = g_object_ref (msg);
1662 info_notify->user_data = info->user_data;
1663 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1664 notify_get_msgs_full,
1667 g_object_unref (msg);
1670 /* Set status failed and set an error */
1671 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1672 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1673 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1674 "Error trying to get a message. No folder found for header");
1676 g_object_unref (header);
1677 tny_iterator_next (iter);
1680 /* Set operation status */
1681 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1682 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1684 /* Notify about operation end */
1685 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1687 /* Free thread resources. Will be called after all previous idles */
1688 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1694 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1695 TnyList *header_list,
1696 GetMsgAsyncUserCallback user_callback,
1698 GDestroyNotify notify)
1700 TnyHeader *header = NULL;
1701 TnyFolder *folder = NULL;
1703 ModestMailOperationPrivate *priv = NULL;
1704 GetFullMsgsInfo *info = NULL;
1705 gboolean size_ok = TRUE;
1707 TnyIterator *iter = NULL;
1709 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1711 /* Init mail operation */
1712 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1713 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1715 priv->total = tny_list_get_length(header_list);
1717 /* Get account and set it into mail_operation */
1718 if (tny_list_get_length (header_list) >= 1) {
1719 iter = tny_list_create_iterator (header_list);
1720 header = TNY_HEADER (tny_iterator_get_current (iter));
1721 folder = tny_header_get_folder (header);
1722 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1723 g_object_unref (header);
1724 g_object_unref (folder);
1726 if (tny_list_get_length (header_list) == 1) {
1727 g_object_unref (iter);
1732 /* Get msg size limit */
1733 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1734 MODEST_CONF_MSG_SIZE_LIMIT,
1737 g_clear_error (&(priv->error));
1738 max_size = G_MAXINT;
1740 max_size = max_size * KB;
1743 /* Check message size limits. If there is only one message
1744 always retrieve it */
1746 while (!tny_iterator_is_done (iter) && size_ok) {
1747 header = TNY_HEADER (tny_iterator_get_current (iter));
1748 if (tny_header_get_message_size (header) >= max_size)
1750 g_object_unref (header);
1751 tny_iterator_next (iter);
1753 g_object_unref (iter);
1757 /* Create the info */
1758 info = g_slice_new0 (GetFullMsgsInfo);
1759 info->mail_op = self;
1760 info->user_callback = user_callback;
1761 info->user_data = user_data;
1762 info->headers = g_object_ref (header_list);
1763 info->notify = notify;
1765 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1767 /* Set status failed and set an error */
1768 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1769 /* FIXME: the error msg is different for pop */
1770 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1771 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1772 _("emev_ni_ui_imap_msg_size_exceed_error"));
1773 /* Remove from queue and free resources */
1774 modest_mail_operation_notify_end (self);
1782 modest_mail_operation_remove_msg (ModestMailOperation *self,
1784 gboolean remove_to_trash)
1787 ModestMailOperationPrivate *priv;
1789 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1790 g_return_if_fail (TNY_IS_HEADER (header));
1792 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1793 folder = tny_header_get_folder (header);
1795 /* Get account and set it into mail_operation */
1796 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1798 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1800 /* Delete or move to trash */
1801 if (remove_to_trash) {
1802 TnyFolder *trash_folder;
1803 TnyStoreAccount *store_account;
1805 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1806 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1807 TNY_FOLDER_TYPE_TRASH);
1812 headers = tny_simple_list_new ();
1813 tny_list_append (headers, G_OBJECT (header));
1814 g_object_unref (header);
1817 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1818 g_object_unref (headers);
1819 /* g_object_unref (trash_folder); */
1821 ModestMailOperationPrivate *priv;
1823 /* Set status failed and set an error */
1824 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1825 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1826 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1827 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1828 _("Error trying to delete a message. Trash folder not found"));
1831 g_object_unref (G_OBJECT (store_account));
1833 tny_folder_remove_msg (folder, header, &(priv->error));
1835 tny_folder_sync(folder, TRUE, &(priv->error));
1840 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1842 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1845 g_object_unref (G_OBJECT (folder));
1847 /* Notify about operation end */
1848 modest_mail_operation_notify_end (self);
1852 transfer_msgs_status_cb (GObject *obj,
1856 XFerMsgAsyncHelper *helper = NULL;
1857 ModestMailOperation *self;
1858 ModestMailOperationPrivate *priv;
1859 ModestMailOperationState *state;
1862 g_return_if_fail (status != NULL);
1863 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1865 helper = (XFerMsgAsyncHelper *) user_data;
1866 g_return_if_fail (helper != NULL);
1868 self = helper->mail_op;
1869 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1871 if ((status->position == 1) && (status->of_total == 100))
1874 priv->done = status->position;
1875 priv->total = status->of_total;
1877 state = modest_mail_operation_clone_state (self);
1878 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1879 g_slice_free (ModestMailOperationState, state);
1884 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1886 XFerMsgAsyncHelper *helper;
1887 ModestMailOperation *self;
1888 ModestMailOperationPrivate *priv;
1890 helper = (XFerMsgAsyncHelper *) user_data;
1891 self = helper->mail_op;
1893 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1896 priv->error = g_error_copy (*err);
1898 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1899 } else if (cancelled) {
1900 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1901 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1902 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1903 _("Error trying to refresh the contents of %s"),
1904 tny_folder_get_name (folder));
1907 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1910 /* If user defined callback function was defined, call it */
1911 if (helper->user_callback) {
1912 helper->user_callback (priv->source, helper->user_data);
1916 g_object_unref (helper->headers);
1917 g_object_unref (helper->dest_folder);
1918 g_object_unref (helper->mail_op);
1919 g_slice_free (XFerMsgAsyncHelper, helper);
1920 g_object_unref (folder);
1922 /* Notify about operation end */
1923 modest_mail_operation_notify_end (self);
1927 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1930 gboolean delete_original,
1931 XferMsgsAsynUserCallback user_callback,
1934 ModestMailOperationPrivate *priv;
1936 TnyFolder *src_folder;
1937 XFerMsgAsyncHelper *helper;
1939 ModestTnyFolderRules rules;
1941 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1942 g_return_if_fail (TNY_IS_LIST (headers));
1943 g_return_if_fail (TNY_IS_FOLDER (folder));
1945 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1948 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1950 /* Apply folder rules */
1951 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1953 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1954 /* Set status failed and set an error */
1955 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1956 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1957 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1958 _("FIXME: folder does not accept msgs"));
1959 /* Notify the queue */
1960 modest_mail_operation_notify_end (self);
1964 /* Create the helper */
1965 helper = g_slice_new0 (XFerMsgAsyncHelper);
1966 helper->mail_op = g_object_ref(self);
1967 helper->dest_folder = g_object_ref(folder);
1968 helper->headers = g_object_ref(headers);
1969 helper->user_callback = user_callback;
1970 helper->user_data = user_data;
1972 /* Get source folder */
1973 iter = tny_list_create_iterator (headers);
1974 header = TNY_HEADER (tny_iterator_get_current (iter));
1975 src_folder = tny_header_get_folder (header);
1976 g_object_unref (header);
1977 g_object_unref (iter);
1979 /* Get account and set it into mail_operation */
1980 priv->account = modest_tny_folder_get_account (src_folder);
1982 /* Transfer messages */
1983 tny_folder_transfer_msgs_async (src_folder,
1988 transfer_msgs_status_cb,
1994 on_refresh_folder (TnyFolder *folder,
1999 RefreshAsyncHelper *helper = NULL;
2000 ModestMailOperation *self = NULL;
2001 ModestMailOperationPrivate *priv = NULL;
2003 helper = (RefreshAsyncHelper *) user_data;
2004 self = helper->mail_op;
2005 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2008 priv->error = g_error_copy (*error);
2009 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2014 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2015 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2016 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2017 _("Error trying to refresh the contents of %s"),
2018 tny_folder_get_name (folder));
2022 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2025 /* Call user defined callback, if it exists */
2026 if (helper->user_callback)
2027 helper->user_callback (priv->source, folder, helper->user_data);
2030 g_object_unref (helper->mail_op);
2031 g_slice_free (RefreshAsyncHelper, helper);
2032 g_object_unref (folder);
2034 /* Notify about operation end */
2035 modest_mail_operation_notify_end (self);
2039 on_refresh_folder_status_update (GObject *obj,
2043 RefreshAsyncHelper *helper = NULL;
2044 ModestMailOperation *self = NULL;
2045 ModestMailOperationPrivate *priv = NULL;
2046 ModestMailOperationState *state;
2048 g_return_if_fail (user_data != NULL);
2049 g_return_if_fail (status != NULL);
2050 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2052 helper = (RefreshAsyncHelper *) user_data;
2053 self = helper->mail_op;
2054 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2056 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2058 priv->done = status->position;
2059 priv->total = status->of_total;
2061 state = modest_mail_operation_clone_state (self);
2062 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2063 g_slice_free (ModestMailOperationState, state);
2067 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2069 RefreshAsyncUserCallback user_callback,
2072 ModestMailOperationPrivate *priv = NULL;
2073 RefreshAsyncHelper *helper = NULL;
2075 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2077 /* Pick a reference */
2078 g_object_ref (folder);
2080 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2082 /* Get account and set it into mail_operation */
2083 priv->account = modest_tny_folder_get_account (folder);
2085 /* Create the helper */
2086 helper = g_slice_new0 (RefreshAsyncHelper);
2087 helper->mail_op = g_object_ref(self);
2088 helper->user_callback = user_callback;
2089 helper->user_data = user_data;
2091 /* Refresh the folder. TODO: tinymail could issue a status
2092 updates before the callback call then this could happen. We
2093 must review the design */
2094 tny_folder_refresh_async (folder,
2096 on_refresh_folder_status_update,
2102 * It's used by the mail operation queue to notify the observers
2103 * attached to that signal that the operation finished. We need to use
2104 * that because tinymail does not give us the progress of a given
2105 * operation when it finishes (it directly calls the operation
2109 modest_mail_operation_notify_end (ModestMailOperation *self)
2111 ModestMailOperationState *state;
2112 ModestMailOperationPrivate *priv = NULL;
2114 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2116 /* Set the account back to not busy */
2117 if (priv->account_name)
2119 modest_account_mgr_set_account_busy(modest_runtime_get_account_mgr(), priv->account_name,
2121 g_free(priv->account_name);
2122 priv->account_name = NULL;
2125 /* Notify the observers about the mail opertation end */
2126 state = modest_mail_operation_clone_state (self);
2127 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2128 g_slice_free (ModestMailOperationState, state);