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;
109 GetMsgAsyncUserCallback user_callback;
113 typedef struct _RefreshAsyncHelper {
114 ModestMailOperation *mail_op;
115 RefreshAsyncUserCallback user_callback;
117 } RefreshAsyncHelper;
119 typedef struct _XFerMsgAsyncHelper
121 ModestMailOperation *mail_op;
123 TnyFolder *dest_folder;
124 XferMsgsAsynUserCallback user_callback;
126 } XFerMsgAsyncHelper;
129 static GObjectClass *parent_class = NULL;
131 static guint signals[NUM_SIGNALS] = {0};
134 modest_mail_operation_get_type (void)
136 static GType my_type = 0;
138 static const GTypeInfo my_info = {
139 sizeof(ModestMailOperationClass),
140 NULL, /* base init */
141 NULL, /* base finalize */
142 (GClassInitFunc) modest_mail_operation_class_init,
143 NULL, /* class finalize */
144 NULL, /* class data */
145 sizeof(ModestMailOperation),
147 (GInstanceInitFunc) modest_mail_operation_init,
150 my_type = g_type_register_static (G_TYPE_OBJECT,
151 "ModestMailOperation",
158 modest_mail_operation_class_init (ModestMailOperationClass *klass)
160 GObjectClass *gobject_class;
161 gobject_class = (GObjectClass*) klass;
163 parent_class = g_type_class_peek_parent (klass);
164 gobject_class->finalize = modest_mail_operation_finalize;
166 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
169 * ModestMailOperation::progress-changed
170 * @self: the #MailOperation that emits the signal
171 * @user_data: user data set when the signal handler was connected
173 * Emitted when the progress of a mail operation changes
175 signals[PROGRESS_CHANGED_SIGNAL] =
176 g_signal_new ("progress-changed",
177 G_TYPE_FROM_CLASS (gobject_class),
179 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
181 g_cclosure_marshal_VOID__POINTER,
182 G_TYPE_NONE, 1, G_TYPE_POINTER);
187 modest_mail_operation_init (ModestMailOperation *obj)
189 ModestMailOperationPrivate *priv;
191 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
193 priv->account = NULL;
194 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
195 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
200 priv->error_checking = NULL;
201 priv->error_checking_user_data = NULL;
205 modest_mail_operation_finalize (GObject *obj)
207 ModestMailOperationPrivate *priv;
209 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
214 g_error_free (priv->error);
218 g_object_unref (priv->source);
222 g_object_unref (priv->account);
223 priv->account = NULL;
227 G_OBJECT_CLASS(parent_class)->finalize (obj);
231 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
234 ModestMailOperation *obj;
235 ModestMailOperationPrivate *priv;
237 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
238 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
240 priv->op_type = op_type;
242 priv->source = g_object_ref(source);
248 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
250 ErrorCheckingUserCallback error_handler,
253 ModestMailOperation *obj;
254 ModestMailOperationPrivate *priv;
256 obj = modest_mail_operation_new (op_type, source);
257 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
259 g_return_val_if_fail (error_handler != NULL, obj);
260 priv->error_checking = error_handler;
266 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
268 ModestMailOperationPrivate *priv;
270 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
271 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
273 if (priv->error_checking != NULL)
274 priv->error_checking (self, priv->error_checking_user_data);
278 ModestMailOperationTypeOperation
279 modest_mail_operation_get_type_operation (ModestMailOperation *self)
281 ModestMailOperationPrivate *priv;
283 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
285 return priv->op_type;
289 modest_mail_operation_is_mine (ModestMailOperation *self,
292 ModestMailOperationPrivate *priv;
294 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
295 if (priv->source == NULL) return FALSE;
297 return priv->source == me;
301 modest_mail_operation_get_source (ModestMailOperation *self)
303 ModestMailOperationPrivate *priv;
305 g_return_val_if_fail (self, NULL);
307 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
309 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
313 return g_object_ref (priv->source);
316 ModestMailOperationStatus
317 modest_mail_operation_get_status (ModestMailOperation *self)
319 ModestMailOperationPrivate *priv;
321 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
322 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
323 MODEST_MAIL_OPERATION_STATUS_INVALID);
325 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
327 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
328 return MODEST_MAIL_OPERATION_STATUS_INVALID;
335 modest_mail_operation_get_error (ModestMailOperation *self)
337 ModestMailOperationPrivate *priv;
339 g_return_val_if_fail (self, NULL);
340 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
342 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
345 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
353 modest_mail_operation_cancel (ModestMailOperation *self)
355 ModestMailOperationPrivate *priv;
357 if (!MODEST_IS_MAIL_OPERATION (self)) {
358 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
362 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
364 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
368 /* Notify about operation end */
369 modest_mail_operation_notify_end (self);
374 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
376 modest_mail_operation_queue_cancel_all (modest_runtime_get_mail_operation_queue());
383 modest_mail_operation_get_task_done (ModestMailOperation *self)
385 ModestMailOperationPrivate *priv;
387 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
389 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
394 modest_mail_operation_get_task_total (ModestMailOperation *self)
396 ModestMailOperationPrivate *priv;
398 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
400 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
405 modest_mail_operation_is_finished (ModestMailOperation *self)
407 ModestMailOperationPrivate *priv;
408 gboolean retval = FALSE;
410 if (!MODEST_IS_MAIL_OPERATION (self)) {
411 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
415 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
417 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
418 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
419 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
420 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
430 modest_mail_operation_get_id (ModestMailOperation *self)
432 ModestMailOperationPrivate *priv;
434 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
436 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
441 modest_mail_operation_set_id (ModestMailOperation *self,
444 ModestMailOperationPrivate *priv;
446 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
448 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
453 * Creates an image of the current state of a mail operation, the
454 * caller must free it
456 static ModestMailOperationState *
457 modest_mail_operation_clone_state (ModestMailOperation *self)
459 ModestMailOperationState *state;
460 ModestMailOperationPrivate *priv;
462 /* FIXME: this should be fixed properly
464 * in some cases, priv was NULL, so checking here to
467 g_return_val_if_fail (self, NULL);
468 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
469 g_return_val_if_fail (priv, NULL);
474 state = g_slice_new (ModestMailOperationState);
476 state->status = priv->status;
477 state->op_type = priv->op_type;
478 state->done = priv->done;
479 state->total = priv->total;
480 state->finished = modest_mail_operation_is_finished (self);
481 state->bytes_done = 0;
482 state->bytes_total = 0;
487 /* ******************************************************************* */
488 /* ************************** SEND ACTIONS ************************* */
489 /* ******************************************************************* */
492 modest_mail_operation_send_mail (ModestMailOperation *self,
493 TnyTransportAccount *transport_account,
496 TnySendQueue *send_queue = NULL;
497 ModestMailOperationPrivate *priv;
499 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
500 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
501 g_return_if_fail (TNY_IS_MSG (msg));
503 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
505 /* Get account and set it into mail_operation */
506 priv->account = g_object_ref (transport_account);
508 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
509 if (!TNY_IS_SEND_QUEUE(send_queue)) {
510 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
511 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
512 "modest: could not find send queue for account\n");
514 tny_send_queue_add (send_queue, msg, &(priv->error));
517 /* Notify about operation end */
518 modest_mail_operation_notify_end (self);
522 modest_mail_operation_send_new_mail (ModestMailOperation *self,
523 TnyTransportAccount *transport_account,
525 const gchar *from, const gchar *to,
526 const gchar *cc, const gchar *bcc,
527 const gchar *subject, const gchar *plain_body,
528 const gchar *html_body,
529 const GList *attachments_list,
530 TnyHeaderFlags priority_flags)
532 TnyMsg *new_msg = NULL;
533 TnyFolder *folder = NULL;
534 TnyHeader *header = NULL;
535 ModestMailOperationPrivate *priv = NULL;
537 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
538 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
540 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
542 /* Get account and set it into mail_operation */
543 priv->account = g_object_ref (transport_account);
545 /* Check parametters */
547 /* Set status failed and set an error */
548 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
549 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
550 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
551 _("Error trying to send a mail. You need to set at least one recipient"));
555 if (html_body == NULL) {
556 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
558 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
561 g_printerr ("modest: failed to create a new msg\n");
565 /* Set priority flags in message */
566 header = tny_msg_get_header (new_msg);
567 if (priority_flags != 0)
568 tny_header_set_flags (header, priority_flags);
570 /* Call mail operation */
571 modest_mail_operation_send_mail (self, transport_account, new_msg);
573 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
575 if (draft_msg != NULL) {
576 header = tny_msg_get_header (draft_msg);
577 /* Note: This can fail (with a warning) if the message is not really already in a folder,
578 * because this function requires it to have a UID. */
579 tny_folder_remove_msg (folder, header, NULL);
580 g_object_unref (header);
585 g_object_unref (G_OBJECT (new_msg));
589 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
590 TnyTransportAccount *transport_account,
592 const gchar *from, const gchar *to,
593 const gchar *cc, const gchar *bcc,
594 const gchar *subject, const gchar *plain_body,
595 const gchar *html_body,
596 const GList *attachments_list,
597 TnyHeaderFlags priority_flags)
600 TnyFolder *folder = NULL;
601 TnyHeader *header = NULL;
602 ModestMailOperationPrivate *priv = NULL;
604 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
605 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
607 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
609 /* Get account and set it into mail_operation */
610 priv->account = g_object_ref (transport_account);
612 if (html_body == NULL) {
613 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
615 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
618 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
619 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
620 "modest: failed to create a new msg\n");
624 /* add priority flags */
625 header = tny_msg_get_header (msg);
626 tny_header_set_flags (header, priority_flags);
628 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
630 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
631 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
632 "modest: failed to create a new msg\n");
636 if (draft_msg != NULL) {
637 header = tny_msg_get_header (draft_msg);
638 /* Remove the old draft expunging it */
639 tny_folder_remove_msg (folder, header, NULL);
640 tny_folder_sync (folder, TRUE, NULL);
641 g_object_unref (header);
644 tny_folder_add_msg (folder, msg, &(priv->error));
650 g_object_unref (G_OBJECT(msg));
652 g_object_unref (G_OBJECT(folder));
654 modest_mail_operation_notify_end (self);
659 ModestMailOperation *mail_op;
660 TnyStoreAccount *account;
661 TnyTransportAccount *transport_account;
664 gchar *retrieve_type;
668 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
669 /* We use this folder observer to track the headers that have been
670 * added to a folder */
673 TnyList *new_headers;
674 } InternalFolderObserver;
678 } InternalFolderObserverClass;
680 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
682 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
683 internal_folder_observer,
685 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
689 foreach_add_item (gpointer header, gpointer user_data)
691 /* printf("DEBUG: %s: header subject=%s\n",
692 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
694 tny_list_prepend (TNY_LIST (user_data),
695 g_object_ref (G_OBJECT (header)));
698 /* This is the method that looks for new messages in a folder */
700 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
702 InternalFolderObserver *derived = (InternalFolderObserver *)self;
704 TnyFolderChangeChanged changed;
706 changed = tny_folder_change_get_changed (change);
708 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
711 /* Get added headers */
712 list = tny_simple_list_new ();
713 tny_folder_change_get_added_headers (change, list);
715 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
716 * __FUNCTION__, tny_list_get_length(list));
719 /* Add them to the folder observer */
720 tny_list_foreach (list, foreach_add_item,
721 derived->new_headers);
723 g_object_unref (G_OBJECT (list));
728 internal_folder_observer_init (InternalFolderObserver *self)
730 self->new_headers = tny_simple_list_new ();
733 internal_folder_observer_finalize (GObject *object)
735 InternalFolderObserver *self;
737 self = (InternalFolderObserver *) object;
738 g_object_unref (self->new_headers);
740 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
743 tny_folder_observer_init (TnyFolderObserverIface *iface)
745 iface->update_func = internal_folder_observer_update;
748 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
750 GObjectClass *object_class;
752 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
753 object_class = (GObjectClass*) klass;
754 object_class->finalize = internal_folder_observer_finalize;
760 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
763 TnyList *folders = tny_simple_list_new ();
765 tny_folder_store_get_folders (store, folders, query, NULL);
766 iter = tny_list_create_iterator (folders);
768 while (!tny_iterator_is_done (iter)) {
770 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
772 tny_list_prepend (all_folders, G_OBJECT (folder));
773 recurse_folders (folder, query, all_folders);
774 g_object_unref (G_OBJECT (folder));
776 tny_iterator_next (iter);
778 g_object_unref (G_OBJECT (iter));
779 g_object_unref (G_OBJECT (folders));
783 * Issues the "progress-changed" signal. The timer won't be removed,
784 * so you must call g_source_remove to stop the signal emission
787 idle_notify_progress (gpointer data)
789 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
790 ModestMailOperationState *state;
792 state = modest_mail_operation_clone_state (mail_op);
793 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
794 g_slice_free (ModestMailOperationState, state);
800 * Issues the "progress-changed" signal and removes the timer. It uses
801 * a lock to ensure that the progress information of the mail
802 * operation is not modified while there are notifications pending
805 idle_notify_progress_once (gpointer data)
809 pair = (ModestPair *) data;
811 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
813 /* Free the state and the reference to the mail operation */
814 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
815 g_object_unref (pair->first);
821 * Used by update_account_thread to notify the queue from the main
822 * loop. We call it inside an idle call to achieve that
825 notify_update_account_queue (gpointer data)
827 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
828 ModestMailOperationPrivate *priv = NULL;
830 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
832 modest_mail_operation_notify_end (mail_op);
833 g_object_unref (mail_op);
839 compare_headers_by_date (gconstpointer a,
842 TnyHeader **header1, **header2;
845 header1 = (TnyHeader **) a;
846 header2 = (TnyHeader **) b;
848 sent1 = tny_header_get_date_sent (*header1);
849 sent2 = tny_header_get_date_sent (*header2);
851 /* We want the most recent ones (greater time_t) at the
860 set_last_updated_idle (gpointer data)
862 /* It does not matter if the time is not exactly the same than
863 the time when this idle was called, it's just an
864 approximation and it won't be very different */
865 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
867 MODEST_ACCOUNT_LAST_UPDATED,
875 update_account_thread (gpointer thr_user_data)
877 static gboolean first_time = TRUE;
878 UpdateAccountInfo *info;
879 TnyList *all_folders = NULL;
880 GPtrArray *new_headers;
881 TnyIterator *iter = NULL;
882 TnyFolderStoreQuery *query = NULL;
883 ModestMailOperationPrivate *priv;
884 ModestTnySendQueue *send_queue;
886 info = (UpdateAccountInfo *) thr_user_data;
887 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
889 /* Get account and set it into mail_operation */
890 priv->account = g_object_ref (info->account);
893 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
894 * show any updates unless we do that
896 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
897 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
899 /* Get all the folders. We can do it synchronously because
900 we're already running in a different thread than the UI */
901 all_folders = tny_simple_list_new ();
902 query = tny_folder_store_query_new ();
903 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
904 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
909 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
913 iter = tny_list_create_iterator (all_folders);
914 while (!tny_iterator_is_done (iter)) {
915 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
917 recurse_folders (folder, query, all_folders);
918 tny_iterator_next (iter);
920 g_object_unref (G_OBJECT (iter));
922 /* Update status and notify. We need to call the notification
923 with a source function in order to call it from the main
924 loop. We need that in order not to get into trouble with
925 Gtk+. We use a timeout in order to provide more status
926 information, because the sync tinymail call does not
927 provide it for the moment */
928 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
930 /* Refresh folders */
931 new_headers = g_ptr_array_new ();
932 iter = tny_list_create_iterator (all_folders);
934 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
936 InternalFolderObserver *observer;
937 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
939 /* Refresh the folder */
940 /* Our observer receives notification of new emails during folder refreshes,
941 * so we can use observer->new_headers.
942 * TODO: This does not seem to be providing accurate numbers.
943 * Possibly the observer is notified asynchronously.
945 observer = g_object_new (internal_folder_observer_get_type (), NULL);
946 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
948 /* This gets the status information (headers) from the server.
949 * We use the blocking version, because we are already in a separate
953 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
954 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
957 /* If the retrieve type is full messages, refresh and get the messages */
958 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
960 iter = tny_list_create_iterator (observer->new_headers);
961 while (!tny_iterator_is_done (iter)) {
962 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
964 /* Apply per-message size limits */
965 if (tny_header_get_message_size (header) < info->max_size)
966 g_ptr_array_add (new_headers, g_object_ref (header));
968 g_object_unref (header);
969 tny_iterator_next (iter);
971 g_object_unref (iter);
973 /* We do not need to do it the first time
974 because it's automatically done by the tree
976 if (G_UNLIKELY (!first_time))
977 tny_folder_poke_status (TNY_FOLDER (folder));
979 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
980 g_object_unref (observer);
984 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
986 g_object_unref (G_OBJECT (folder));
987 tny_iterator_next (iter);
990 did_a_cancel = FALSE;
992 g_object_unref (G_OBJECT (iter));
993 g_source_remove (timeout);
995 if (new_headers->len > 0) {
999 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1001 /* Apply message count limit */
1002 /* If the number of messages exceeds the maximum, ask the
1003 * user to download them all,
1004 * as per the UI spec "Retrieval Limits" section in 4.4:
1006 printf ("************************** DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
1007 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
1008 if (new_headers->len > info->retrieve_limit) {
1009 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
1010 * with 'Get all' and 'Newest only' buttons. */
1011 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1012 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1013 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1014 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1015 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1020 priv->total = MIN (new_headers->len, info->retrieve_limit);
1021 while (msg_num < priv->total) {
1023 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1024 TnyFolder *folder = tny_header_get_folder (header);
1025 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1026 ModestMailOperationState *state;
1030 /* We can not just use the mail operation because the
1031 values of done and total could change before the
1033 state = modest_mail_operation_clone_state (info->mail_op);
1034 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1035 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1036 pair, (GDestroyNotify) modest_pair_free);
1038 g_object_unref (msg);
1039 g_object_unref (folder);
1043 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1044 g_ptr_array_free (new_headers, FALSE);
1048 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1051 if (priv->account != NULL)
1052 g_object_unref (priv->account);
1053 priv->account = g_object_ref (info->transport_account);
1055 send_queue = modest_runtime_get_send_queue (info->transport_account);
1057 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
1058 modest_tny_send_queue_try_to_send (send_queue);
1059 g_source_remove (timeout);
1061 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1062 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1063 "cannot create a send queue for %s\n",
1064 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1065 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1068 /* Check if the operation was a success */
1070 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1072 /* Update the last updated key */
1073 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1074 set_last_updated_idle,
1075 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1076 (GDestroyNotify) g_free);
1080 /* Notify about operation end. Note that the info could be
1081 freed before this idle happens, but the mail operation will
1083 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1086 g_object_unref (query);
1087 g_object_unref (all_folders);
1088 g_object_unref (info->account);
1089 g_object_unref (info->transport_account);
1090 g_free (info->retrieve_type);
1091 g_slice_free (UpdateAccountInfo, info);
1099 modest_mail_operation_update_account (ModestMailOperation *self,
1100 const gchar *account_name)
1103 UpdateAccountInfo *info;
1104 ModestMailOperationPrivate *priv;
1105 ModestAccountMgr *mgr;
1106 TnyStoreAccount *modest_account;
1107 TnyTransportAccount *transport_account;
1109 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1110 g_return_val_if_fail (account_name, FALSE);
1112 /* Make sure that we have a connection, and request one
1114 * TODO: Is there some way to trigger this for every attempt to
1115 * use the network? */
1116 if (!modest_platform_connect_and_wait(NULL))
1119 /* Init mail operation. Set total and done to 0, and do not
1120 update them, this way the progress objects will know that
1121 we have no clue about the number of the objects */
1122 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1125 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1127 /* Get the Modest account */
1128 modest_account = (TnyStoreAccount *)
1129 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1131 TNY_ACCOUNT_TYPE_STORE);
1133 if (!modest_account) {
1134 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1135 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1136 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1137 "cannot get tny store account for %s\n", account_name);
1138 modest_mail_operation_notify_end (self);
1144 /* Get the transport account, we can not do it in the thread
1145 due to some problems with dbus */
1146 transport_account = (TnyTransportAccount *)
1147 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1149 if (!transport_account) {
1150 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1151 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1152 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1153 "cannot get tny transport account for %s\n", account_name);
1154 modest_mail_operation_notify_end (self);
1159 /* Create the helper object */
1160 info = g_slice_new (UpdateAccountInfo);
1161 info->mail_op = self;
1162 info->account = modest_account;
1163 info->transport_account = transport_account;
1165 /* Get the message size limit */
1166 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1167 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1168 if (info->max_size == 0)
1169 info->max_size = G_MAXINT;
1171 info->max_size = info->max_size * KB;
1173 /* Get per-account retrieval type */
1174 mgr = modest_runtime_get_account_mgr ();
1175 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1176 MODEST_ACCOUNT_RETRIEVE, FALSE);
1178 /* Get per-account message amount retrieval limit */
1179 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1180 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1181 if (info->retrieve_limit == 0)
1182 info->retrieve_limit = G_MAXINT;
1184 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1186 /* Set account busy */
1187 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1188 priv->account_name = g_strdup(account_name);
1190 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1195 /* ******************************************************************* */
1196 /* ************************** STORE ACTIONS ************************* */
1197 /* ******************************************************************* */
1201 modest_mail_operation_create_folder (ModestMailOperation *self,
1202 TnyFolderStore *parent,
1205 ModestMailOperationPrivate *priv;
1206 TnyFolder *new_folder = NULL;
1208 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1209 g_return_val_if_fail (name, NULL);
1211 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1214 if (TNY_IS_FOLDER (parent)) {
1215 /* Check folder rules */
1216 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1217 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1218 /* Set status failed and set an error */
1219 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1220 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1221 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1222 _("mail_in_ui_folder_create_error"));
1227 /* Create the folder */
1228 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1229 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1231 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1234 /* Notify about operation end */
1235 modest_mail_operation_notify_end (self);
1241 modest_mail_operation_remove_folder (ModestMailOperation *self,
1243 gboolean remove_to_trash)
1245 TnyAccount *account;
1246 ModestMailOperationPrivate *priv;
1247 ModestTnyFolderRules rules;
1249 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1250 g_return_if_fail (TNY_IS_FOLDER (folder));
1252 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1254 /* Check folder rules */
1255 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1256 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1257 /* Set status failed and set an error */
1258 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1259 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1260 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1261 _("mail_in_ui_folder_delete_error"));
1265 /* Get the account */
1266 account = modest_tny_folder_get_account (folder);
1267 priv->account = g_object_ref(account);
1269 /* Delete folder or move to trash */
1270 if (remove_to_trash) {
1271 TnyFolder *trash_folder = NULL;
1272 trash_folder = modest_tny_account_get_special_folder (account,
1273 TNY_FOLDER_TYPE_TRASH);
1274 /* TODO: error_handling */
1275 modest_mail_operation_xfer_folder (self, folder,
1276 TNY_FOLDER_STORE (trash_folder), TRUE);
1278 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1280 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1281 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1284 g_object_unref (G_OBJECT (parent));
1286 g_object_unref (G_OBJECT (account));
1289 /* Notify about operation end */
1290 modest_mail_operation_notify_end (self);
1294 transfer_folder_status_cb (GObject *obj,
1298 ModestMailOperation *self;
1299 ModestMailOperationPrivate *priv;
1300 ModestMailOperationState *state;
1302 g_return_if_fail (status != NULL);
1303 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1305 self = MODEST_MAIL_OPERATION (user_data);
1306 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1308 if ((status->position == 1) && (status->of_total == 100))
1311 priv->done = status->position;
1312 priv->total = status->of_total;
1314 state = modest_mail_operation_clone_state (self);
1315 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1316 g_slice_free (ModestMailOperationState, state);
1321 transfer_folder_cb (TnyFolder *folder,
1322 TnyFolderStore *into,
1324 TnyFolder *new_folder, GError **err,
1327 ModestMailOperation *self = NULL;
1328 ModestMailOperationPrivate *priv = NULL;
1330 self = MODEST_MAIL_OPERATION (user_data);
1332 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1335 priv->error = g_error_copy (*err);
1337 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1338 } else if (cancelled) {
1339 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1340 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1341 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1342 _("Transference of %s was cancelled."),
1343 tny_folder_get_name (folder));
1346 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1350 g_object_unref (folder);
1351 g_object_unref (into);
1352 if (new_folder != NULL)
1353 g_object_unref (new_folder);
1355 /* Notify about operation end */
1356 modest_mail_operation_notify_end (self);
1360 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1362 TnyFolderStore *parent,
1363 gboolean delete_original)
1365 ModestMailOperationPrivate *priv = NULL;
1366 ModestTnyFolderRules parent_rules, rules;
1368 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1369 g_return_if_fail (TNY_IS_FOLDER (folder));
1370 g_return_if_fail (TNY_IS_FOLDER (parent));
1372 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1374 /* Get account and set it into mail_operation */
1375 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1376 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1378 /* Get folder rules */
1379 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1380 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1382 if (!TNY_IS_FOLDER_STORE (parent)) {
1386 /* The moveable restriction is applied also to copy operation */
1387 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1388 /* Set status failed and set an error */
1389 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1390 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1391 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1392 _("mail_in_ui_folder_move_target_error"));
1394 /* Notify the queue */
1395 modest_mail_operation_notify_end (self);
1396 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1397 /* Set status failed and set an error */
1398 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1399 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1400 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1401 _("FIXME: parent folder does not accept new folders"));
1403 /* Notify the queue */
1404 modest_mail_operation_notify_end (self);
1406 /* Pick references for async calls */
1407 g_object_ref (folder);
1408 g_object_ref (parent);
1410 /* Move/Copy folder */
1411 tny_folder_copy_async (folder,
1413 tny_folder_get_name (folder),
1416 transfer_folder_status_cb,
1422 modest_mail_operation_rename_folder (ModestMailOperation *self,
1426 ModestMailOperationPrivate *priv;
1427 ModestTnyFolderRules rules;
1429 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1430 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1431 g_return_if_fail (name);
1433 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1435 /* Get account and set it into mail_operation */
1436 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1438 /* Check folder rules */
1439 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1440 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1441 /* Set status failed and set an error */
1442 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1443 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1444 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1445 _("FIXME: unable to rename"));
1447 /* Notify about operation end */
1448 modest_mail_operation_notify_end (self);
1450 /* Rename. Camel handles folder subscription/unsubscription */
1451 TnyFolderStore *into;
1453 into = tny_folder_get_folder_store (folder);
1454 tny_folder_copy_async (folder, into, name, TRUE,
1456 transfer_folder_status_cb,
1459 g_object_unref (into);
1464 /* ******************************************************************* */
1465 /* ************************** MSG ACTIONS ************************* */
1466 /* ******************************************************************* */
1468 void modest_mail_operation_get_msg (ModestMailOperation *self,
1470 GetMsgAsyncUserCallback user_callback,
1473 GetMsgAsyncHelper *helper = NULL;
1475 ModestMailOperationPrivate *priv;
1477 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1478 g_return_if_fail (TNY_IS_HEADER (header));
1480 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1481 folder = tny_header_get_folder (header);
1483 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1485 /* Get message from folder */
1487 /* Get account and set it into mail_operation */
1488 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1490 helper = g_slice_new0 (GetMsgAsyncHelper);
1491 helper->mail_op = self;
1492 helper->user_callback = user_callback;
1493 helper->user_data = user_data;
1494 helper->header = g_object_ref (header);
1496 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1498 g_object_unref (G_OBJECT (folder));
1500 /* Set status failed and set an error */
1501 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1502 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1503 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1504 _("Error trying to get a message. No folder found for header"));
1506 /* Notify the queue */
1507 modest_mail_operation_notify_end (self);
1512 get_msg_cb (TnyFolder *folder,
1518 GetMsgAsyncHelper *helper = NULL;
1519 ModestMailOperation *self = NULL;
1520 ModestMailOperationPrivate *priv = NULL;
1522 helper = (GetMsgAsyncHelper *) user_data;
1523 g_return_if_fail (helper != NULL);
1524 self = helper->mail_op;
1525 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1526 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1528 /* Check errors and cancel */
1530 priv->error = g_error_copy (*error);
1531 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1535 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1536 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1537 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1538 _("Error trying to refresh the contents of %s"),
1539 tny_folder_get_name (folder));
1543 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1545 /* If user defined callback function was defined, call it */
1546 if (helper->user_callback) {
1547 helper->user_callback (self, helper->header, msg, helper->user_data);
1552 g_object_unref (helper->header);
1553 g_slice_free (GetMsgAsyncHelper, helper);
1555 /* Notify about operation end */
1556 modest_mail_operation_notify_end (self);
1560 get_msg_status_cb (GObject *obj,
1564 GetMsgAsyncHelper *helper = NULL;
1565 ModestMailOperation *self;
1566 ModestMailOperationPrivate *priv;
1567 ModestMailOperationState *state;
1569 g_return_if_fail (status != NULL);
1570 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1572 helper = (GetMsgAsyncHelper *) user_data;
1573 g_return_if_fail (helper != NULL);
1575 self = helper->mail_op;
1576 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1578 if ((status->position == 1) && (status->of_total == 100))
1584 state = modest_mail_operation_clone_state (self);
1585 state->bytes_done = status->position;
1586 state->bytes_total = status->of_total;
1587 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1588 g_slice_free (ModestMailOperationState, state);
1591 /****************************************************/
1593 ModestMailOperation *mail_op;
1595 GetMsgAsyncUserCallback user_callback;
1597 GDestroyNotify notify;
1601 GetMsgAsyncUserCallback user_callback;
1605 ModestMailOperation *mail_op;
1606 } NotifyGetMsgsInfo;
1610 * Used by get_msgs_full_thread to call the user_callback for each
1611 * message that has been read
1614 notify_get_msgs_full (gpointer data)
1616 NotifyGetMsgsInfo *info;
1618 info = (NotifyGetMsgsInfo *) data;
1620 /* Call the user callback */
1621 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1623 g_slice_free (NotifyGetMsgsInfo, info);
1629 * Used by get_msgs_full_thread to free al the thread resources and to
1630 * call the destroy function for the passed user_data
1633 get_msgs_full_destroyer (gpointer data)
1635 GetFullMsgsInfo *info;
1637 info = (GetFullMsgsInfo *) data;
1640 info->notify (info->user_data);
1643 g_object_unref (info->headers);
1644 g_slice_free (GetFullMsgsInfo, info);
1650 get_msgs_full_thread (gpointer thr_user_data)
1652 GetFullMsgsInfo *info;
1653 ModestMailOperationPrivate *priv = NULL;
1654 TnyIterator *iter = NULL;
1656 info = (GetFullMsgsInfo *) thr_user_data;
1657 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1659 iter = tny_list_create_iterator (info->headers);
1660 while (!tny_iterator_is_done (iter)) {
1664 header = TNY_HEADER (tny_iterator_get_current (iter));
1665 folder = tny_header_get_folder (header);
1667 /* Get message from folder */
1670 /* The callback will call it per each header */
1671 msg = tny_folder_get_msg (folder, header, &(priv->error));
1674 ModestMailOperationState *state;
1679 /* notify progress */
1680 state = modest_mail_operation_clone_state (info->mail_op);
1681 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1682 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1683 pair, (GDestroyNotify) modest_pair_free);
1685 /* The callback is the responsible for
1686 freeing the message */
1687 if (info->user_callback) {
1688 NotifyGetMsgsInfo *info_notify;
1689 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1690 info_notify->user_callback = info->user_callback;
1691 info_notify->mail_op = info->mail_op;
1692 info_notify->header = g_object_ref (header);
1693 info_notify->msg = g_object_ref (msg);
1694 info_notify->user_data = info->user_data;
1695 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1696 notify_get_msgs_full,
1699 g_object_unref (msg);
1702 /* Set status failed and set an error */
1703 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1704 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1705 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1706 "Error trying to get a message. No folder found for header");
1708 g_object_unref (header);
1709 tny_iterator_next (iter);
1712 /* Set operation status */
1713 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1714 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1716 /* Notify about operation end */
1717 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1719 /* Free thread resources. Will be called after all previous idles */
1720 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1726 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1727 TnyList *header_list,
1728 GetMsgAsyncUserCallback user_callback,
1730 GDestroyNotify notify)
1732 TnyHeader *header = NULL;
1733 TnyFolder *folder = NULL;
1735 ModestMailOperationPrivate *priv = NULL;
1736 GetFullMsgsInfo *info = NULL;
1737 gboolean size_ok = TRUE;
1739 TnyIterator *iter = NULL;
1741 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1743 /* Init mail operation */
1744 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1745 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1747 priv->total = tny_list_get_length(header_list);
1749 /* Get account and set it into mail_operation */
1750 if (tny_list_get_length (header_list) >= 1) {
1751 iter = tny_list_create_iterator (header_list);
1752 header = TNY_HEADER (tny_iterator_get_current (iter));
1753 folder = tny_header_get_folder (header);
1754 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1755 g_object_unref (header);
1756 g_object_unref (folder);
1758 if (tny_list_get_length (header_list) == 1) {
1759 g_object_unref (iter);
1764 /* Get msg size limit */
1765 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1766 MODEST_CONF_MSG_SIZE_LIMIT,
1769 g_clear_error (&(priv->error));
1770 max_size = G_MAXINT;
1772 max_size = max_size * KB;
1775 /* Check message size limits. If there is only one message
1776 always retrieve it */
1778 while (!tny_iterator_is_done (iter) && size_ok) {
1779 header = TNY_HEADER (tny_iterator_get_current (iter));
1780 if (tny_header_get_message_size (header) >= max_size)
1782 g_object_unref (header);
1783 tny_iterator_next (iter);
1785 g_object_unref (iter);
1789 /* Create the info */
1790 info = g_slice_new0 (GetFullMsgsInfo);
1791 info->mail_op = self;
1792 info->user_callback = user_callback;
1793 info->user_data = user_data;
1794 info->headers = g_object_ref (header_list);
1795 info->notify = notify;
1797 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1799 /* Set status failed and set an error */
1800 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1801 /* FIXME: the error msg is different for pop */
1802 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1803 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1804 _("emev_ni_ui_imap_msg_size_exceed_error"));
1805 /* Remove from queue and free resources */
1806 modest_mail_operation_notify_end (self);
1814 modest_mail_operation_remove_msg (ModestMailOperation *self,
1816 gboolean remove_to_trash)
1819 ModestMailOperationPrivate *priv;
1821 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1822 g_return_if_fail (TNY_IS_HEADER (header));
1824 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1825 folder = tny_header_get_folder (header);
1827 /* Get account and set it into mail_operation */
1828 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1830 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1832 /* Delete or move to trash */
1833 if (remove_to_trash) {
1834 TnyFolder *trash_folder;
1835 TnyStoreAccount *store_account;
1837 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1838 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1839 TNY_FOLDER_TYPE_TRASH);
1844 headers = tny_simple_list_new ();
1845 tny_list_append (headers, G_OBJECT (header));
1846 g_object_unref (header);
1849 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1850 g_object_unref (headers);
1851 /* g_object_unref (trash_folder); */
1853 ModestMailOperationPrivate *priv;
1855 /* Set status failed and set an error */
1856 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1857 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1858 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1859 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1860 _("Error trying to delete a message. Trash folder not found"));
1863 g_object_unref (G_OBJECT (store_account));
1865 tny_folder_remove_msg (folder, header, &(priv->error));
1867 tny_folder_sync(folder, TRUE, &(priv->error));
1872 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1874 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1877 g_object_unref (G_OBJECT (folder));
1879 /* Notify about operation end */
1880 modest_mail_operation_notify_end (self);
1884 transfer_msgs_status_cb (GObject *obj,
1888 XFerMsgAsyncHelper *helper = NULL;
1889 ModestMailOperation *self;
1890 ModestMailOperationPrivate *priv;
1891 ModestMailOperationState *state;
1894 g_return_if_fail (status != NULL);
1895 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1897 helper = (XFerMsgAsyncHelper *) user_data;
1898 g_return_if_fail (helper != NULL);
1900 self = helper->mail_op;
1901 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1903 if ((status->position == 1) && (status->of_total == 100))
1906 priv->done = status->position;
1907 priv->total = status->of_total;
1909 state = modest_mail_operation_clone_state (self);
1910 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1911 g_slice_free (ModestMailOperationState, state);
1916 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1918 XFerMsgAsyncHelper *helper;
1919 ModestMailOperation *self;
1920 ModestMailOperationPrivate *priv;
1922 helper = (XFerMsgAsyncHelper *) user_data;
1923 self = helper->mail_op;
1925 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1928 priv->error = g_error_copy (*err);
1930 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1931 } else if (cancelled) {
1932 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1933 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1934 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1935 _("Error trying to refresh the contents of %s"),
1936 tny_folder_get_name (folder));
1939 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1942 /* If user defined callback function was defined, call it */
1943 if (helper->user_callback) {
1944 helper->user_callback (priv->source, helper->user_data);
1948 g_object_unref (helper->headers);
1949 g_object_unref (helper->dest_folder);
1950 g_object_unref (helper->mail_op);
1951 g_slice_free (XFerMsgAsyncHelper, helper);
1952 g_object_unref (folder);
1954 /* Notify about operation end */
1955 modest_mail_operation_notify_end (self);
1959 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1962 gboolean delete_original,
1963 XferMsgsAsynUserCallback user_callback,
1966 ModestMailOperationPrivate *priv;
1968 TnyFolder *src_folder;
1969 XFerMsgAsyncHelper *helper;
1971 ModestTnyFolderRules rules;
1973 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1974 g_return_if_fail (TNY_IS_LIST (headers));
1975 g_return_if_fail (TNY_IS_FOLDER (folder));
1977 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1980 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1982 /* Apply folder rules */
1983 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1985 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1986 /* Set status failed and set an error */
1987 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1988 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1989 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1990 _("FIXME: folder does not accept msgs"));
1991 /* Notify the queue */
1992 modest_mail_operation_notify_end (self);
1996 /* Create the helper */
1997 helper = g_slice_new0 (XFerMsgAsyncHelper);
1998 helper->mail_op = g_object_ref(self);
1999 helper->dest_folder = g_object_ref(folder);
2000 helper->headers = g_object_ref(headers);
2001 helper->user_callback = user_callback;
2002 helper->user_data = user_data;
2004 /* Get source folder */
2005 iter = tny_list_create_iterator (headers);
2006 header = TNY_HEADER (tny_iterator_get_current (iter));
2007 src_folder = tny_header_get_folder (header);
2008 g_object_unref (header);
2009 g_object_unref (iter);
2011 /* Get account and set it into mail_operation */
2012 priv->account = modest_tny_folder_get_account (src_folder);
2014 /* Transfer messages */
2015 tny_folder_transfer_msgs_async (src_folder,
2020 transfer_msgs_status_cb,
2026 on_refresh_folder (TnyFolder *folder,
2031 RefreshAsyncHelper *helper = NULL;
2032 ModestMailOperation *self = NULL;
2033 ModestMailOperationPrivate *priv = NULL;
2035 helper = (RefreshAsyncHelper *) user_data;
2036 self = helper->mail_op;
2037 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2040 priv->error = g_error_copy (*error);
2041 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2046 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2047 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2048 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2049 _("Error trying to refresh the contents of %s"),
2050 tny_folder_get_name (folder));
2054 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2057 /* Call user defined callback, if it exists */
2058 if (helper->user_callback)
2059 helper->user_callback (priv->source, folder, helper->user_data);
2062 g_object_unref (helper->mail_op);
2063 g_slice_free (RefreshAsyncHelper, helper);
2064 g_object_unref (folder);
2066 /* Notify about operation end */
2067 modest_mail_operation_notify_end (self);
2071 on_refresh_folder_status_update (GObject *obj,
2075 RefreshAsyncHelper *helper = NULL;
2076 ModestMailOperation *self = NULL;
2077 ModestMailOperationPrivate *priv = NULL;
2078 ModestMailOperationState *state;
2080 g_return_if_fail (user_data != NULL);
2081 g_return_if_fail (status != NULL);
2082 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2084 helper = (RefreshAsyncHelper *) user_data;
2085 self = helper->mail_op;
2086 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2088 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2090 priv->done = status->position;
2091 priv->total = status->of_total;
2093 state = modest_mail_operation_clone_state (self);
2094 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2095 g_slice_free (ModestMailOperationState, state);
2099 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2101 RefreshAsyncUserCallback user_callback,
2104 ModestMailOperationPrivate *priv = NULL;
2105 RefreshAsyncHelper *helper = NULL;
2107 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2109 /* Pick a reference */
2110 g_object_ref (folder);
2112 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2114 /* Get account and set it into mail_operation */
2115 priv->account = modest_tny_folder_get_account (folder);
2117 /* Create the helper */
2118 helper = g_slice_new0 (RefreshAsyncHelper);
2119 helper->mail_op = g_object_ref(self);
2120 helper->user_callback = user_callback;
2121 helper->user_data = user_data;
2123 /* Refresh the folder. TODO: tinymail could issue a status
2124 updates before the callback call then this could happen. We
2125 must review the design */
2126 tny_folder_refresh_async (folder,
2128 on_refresh_folder_status_update,
2134 * It's used by the mail operation queue to notify the observers
2135 * attached to that signal that the operation finished. We need to use
2136 * that because tinymail does not give us the progress of a given
2137 * operation when it finishes (it directly calls the operation
2141 modest_mail_operation_notify_end (ModestMailOperation *self)
2143 ModestMailOperationState *state;
2144 ModestMailOperationPrivate *priv = NULL;
2146 g_return_if_fail (self);
2148 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2151 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
2155 /* Set the account back to not busy */
2156 if (priv->account_name) {
2157 modest_account_mgr_set_account_busy(modest_runtime_get_account_mgr(), priv->account_name,
2159 g_free(priv->account_name);
2160 priv->account_name = NULL;
2163 /* Notify the observers about the mail opertation end */
2164 state = modest_mail_operation_clone_state (self);
2165 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2166 g_slice_free (ModestMailOperationState, state);