1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-camel-pop-store-account.h>
38 #include <tny-simple-list.h>
39 #include <tny-send-queue.h>
40 #include <tny-status.h>
41 #include <tny-folder-observer.h>
42 #include <camel/camel-stream-mem.h>
43 #include <glib/gi18n.h>
44 #include "modest-platform.h"
45 #include <modest-tny-account.h>
46 #include <modest-tny-send-queue.h>
47 #include <modest-runtime.h>
48 #include "modest-text-utils.h"
49 #include "modest-tny-msg.h"
50 #include "modest-tny-folder.h"
51 #include "modest-tny-platform-factory.h"
52 #include "modest-marshal.h"
53 #include "modest-error.h"
54 #include "modest-mail-operation.h"
58 /* 'private'/'protected' functions */
59 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
60 static void modest_mail_operation_init (ModestMailOperation *obj);
61 static void modest_mail_operation_finalize (GObject *obj);
63 static void get_msg_cb (TnyFolder *folder,
69 static void get_msg_status_cb (GObject *obj,
73 static void modest_mail_operation_notify_end (ModestMailOperation *self);
75 static gboolean did_a_cancel = FALSE;
77 enum _ModestMailOperationSignals
79 PROGRESS_CHANGED_SIGNAL,
84 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
85 struct _ModestMailOperationPrivate {
91 ErrorCheckingUserCallback error_checking;
92 gpointer error_checking_user_data;
93 ModestMailOperationStatus status;
94 ModestMailOperationTypeOperation op_type;
97 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
98 MODEST_TYPE_MAIL_OPERATION, \
99 ModestMailOperationPrivate))
101 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
102 priv->status = new_status;\
105 typedef struct _GetMsgAsyncHelper {
106 ModestMailOperation *mail_op;
107 GetMsgAsyncUserCallback user_callback;
112 typedef struct _XFerMsgAsyncHelper
114 ModestMailOperation *mail_op;
116 TnyFolder *dest_folder;
117 XferMsgsAsynUserCallback user_callback;
119 } XFerMsgAsyncHelper;
122 static GObjectClass *parent_class = NULL;
124 static guint signals[NUM_SIGNALS] = {0};
127 modest_mail_operation_get_type (void)
129 static GType my_type = 0;
131 static const GTypeInfo my_info = {
132 sizeof(ModestMailOperationClass),
133 NULL, /* base init */
134 NULL, /* base finalize */
135 (GClassInitFunc) modest_mail_operation_class_init,
136 NULL, /* class finalize */
137 NULL, /* class data */
138 sizeof(ModestMailOperation),
140 (GInstanceInitFunc) modest_mail_operation_init,
143 my_type = g_type_register_static (G_TYPE_OBJECT,
144 "ModestMailOperation",
151 modest_mail_operation_class_init (ModestMailOperationClass *klass)
153 GObjectClass *gobject_class;
154 gobject_class = (GObjectClass*) klass;
156 parent_class = g_type_class_peek_parent (klass);
157 gobject_class->finalize = modest_mail_operation_finalize;
159 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
162 * ModestMailOperation::progress-changed
163 * @self: the #MailOperation that emits the signal
164 * @user_data: user data set when the signal handler was connected
166 * Emitted when the progress of a mail operation changes
168 signals[PROGRESS_CHANGED_SIGNAL] =
169 g_signal_new ("progress-changed",
170 G_TYPE_FROM_CLASS (gobject_class),
172 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
174 g_cclosure_marshal_VOID__POINTER,
175 G_TYPE_NONE, 1, G_TYPE_POINTER);
180 modest_mail_operation_init (ModestMailOperation *obj)
182 ModestMailOperationPrivate *priv;
184 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
186 priv->account = NULL;
187 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
188 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
193 priv->error_checking = NULL;
194 priv->error_checking_user_data = NULL;
198 modest_mail_operation_finalize (GObject *obj)
200 ModestMailOperationPrivate *priv;
202 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
205 g_error_free (priv->error);
209 g_object_unref (priv->source);
213 g_object_unref (priv->account);
214 priv->account = NULL;
218 G_OBJECT_CLASS(parent_class)->finalize (obj);
222 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
225 ModestMailOperation *obj;
226 ModestMailOperationPrivate *priv;
228 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
229 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
231 priv->op_type = op_type;
233 priv->source = g_object_ref(source);
239 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
241 ErrorCheckingUserCallback error_handler,
244 ModestMailOperation *obj;
245 ModestMailOperationPrivate *priv;
247 obj = modest_mail_operation_new (op_type, source);
248 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
250 g_return_val_if_fail (error_handler != NULL, obj);
251 priv->error_checking = error_handler;
257 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
259 ModestMailOperationPrivate *priv;
261 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
262 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
264 if (priv->error_checking != NULL)
265 priv->error_checking (self, priv->error_checking_user_data);
269 ModestMailOperationTypeOperation
270 modest_mail_operation_get_type_operation (ModestMailOperation *self)
272 ModestMailOperationPrivate *priv;
274 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
276 return priv->op_type;
280 modest_mail_operation_is_mine (ModestMailOperation *self,
283 ModestMailOperationPrivate *priv;
285 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
286 if (priv->source == NULL) return FALSE;
288 return priv->source == me;
292 modest_mail_operation_get_source (ModestMailOperation *self)
294 ModestMailOperationPrivate *priv;
296 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
298 return g_object_ref (priv->source);
301 ModestMailOperationStatus
302 modest_mail_operation_get_status (ModestMailOperation *self)
304 ModestMailOperationPrivate *priv;
306 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
307 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
308 MODEST_MAIL_OPERATION_STATUS_INVALID);
310 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
315 modest_mail_operation_get_error (ModestMailOperation *self)
317 ModestMailOperationPrivate *priv;
319 g_return_val_if_fail (self, NULL);
320 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
322 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
327 modest_mail_operation_cancel (ModestMailOperation *self)
329 ModestMailOperationPrivate *priv;
331 if (!MODEST_IS_MAIL_OPERATION (self)) {
332 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
336 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
338 /* cancel current operation in account */
339 tny_account_cancel (priv->account);
344 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
346 /* Notify about operation end */
347 modest_mail_operation_notify_end (self);
353 modest_mail_operation_get_task_done (ModestMailOperation *self)
355 ModestMailOperationPrivate *priv;
357 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
359 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
364 modest_mail_operation_get_task_total (ModestMailOperation *self)
366 ModestMailOperationPrivate *priv;
368 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
370 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
375 modest_mail_operation_is_finished (ModestMailOperation *self)
377 ModestMailOperationPrivate *priv;
378 gboolean retval = FALSE;
380 if (!MODEST_IS_MAIL_OPERATION (self)) {
381 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
385 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
387 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
388 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
389 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
390 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
400 modest_mail_operation_get_id (ModestMailOperation *self)
402 ModestMailOperationPrivate *priv;
404 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
406 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
411 modest_mail_operation_set_id (ModestMailOperation *self,
414 ModestMailOperationPrivate *priv;
416 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
418 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
423 * Creates an image of the current state of a mail operation, the
424 * caller must free it
426 static ModestMailOperationState *
427 modest_mail_operation_clone_state (ModestMailOperation *self)
429 ModestMailOperationState *state;
430 ModestMailOperationPrivate *priv;
432 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
434 state = g_slice_new (ModestMailOperationState);
436 state->status = priv->status;
437 state->op_type = priv->op_type;
438 state->done = priv->done;
439 state->total = priv->total;
440 state->finished = modest_mail_operation_is_finished (self);
445 /* ******************************************************************* */
446 /* ************************** SEND ACTIONS ************************* */
447 /* ******************************************************************* */
450 modest_mail_operation_send_mail (ModestMailOperation *self,
451 TnyTransportAccount *transport_account,
454 TnySendQueue *send_queue = NULL;
455 ModestMailOperationPrivate *priv;
457 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
458 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
459 g_return_if_fail (TNY_IS_MSG (msg));
461 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
463 /* Get account and set it into mail_operation */
464 priv->account = g_object_ref (transport_account);
466 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
467 if (!TNY_IS_SEND_QUEUE(send_queue)) {
468 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
469 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
470 "modest: could not find send queue for account\n");
472 tny_send_queue_add (send_queue, msg, &(priv->error));
475 /* Notify about operation end */
476 modest_mail_operation_notify_end (self);
480 modest_mail_operation_send_new_mail (ModestMailOperation *self,
481 TnyTransportAccount *transport_account,
483 const gchar *from, const gchar *to,
484 const gchar *cc, const gchar *bcc,
485 const gchar *subject, const gchar *plain_body,
486 const gchar *html_body,
487 const GList *attachments_list,
488 TnyHeaderFlags priority_flags)
490 TnyMsg *new_msg = NULL;
491 TnyFolder *folder = NULL;
492 TnyHeader *header = NULL;
493 ModestMailOperationPrivate *priv = NULL;
495 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
496 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
498 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
500 /* Get account and set it into mail_operation */
501 priv->account = g_object_ref (transport_account);
503 /* Check parametters */
505 /* Set status failed and set an error */
506 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
507 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
508 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
509 _("Error trying to send a mail. You need to set at least one recipient"));
513 if (html_body == NULL) {
514 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
516 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
519 g_printerr ("modest: failed to create a new msg\n");
523 /* Set priority flags in message */
524 header = tny_msg_get_header (new_msg);
525 tny_header_set_flags (header, priority_flags);
527 /* Call mail operation */
528 modest_mail_operation_send_mail (self, transport_account, new_msg);
530 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
532 if (draft_msg != NULL) {
533 header = tny_msg_get_header (draft_msg);
534 /* Note: This can fail (with a warning) if the message is not really already in a folder,
535 * because this function requires it to have a UID. */
536 tny_folder_remove_msg (folder, header, NULL);
537 g_object_unref (header);
542 g_object_unref (G_OBJECT (new_msg));
546 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
547 TnyTransportAccount *transport_account,
549 const gchar *from, const gchar *to,
550 const gchar *cc, const gchar *bcc,
551 const gchar *subject, const gchar *plain_body,
552 const gchar *html_body,
553 const GList *attachments_list,
554 TnyHeaderFlags priority_flags)
557 TnyFolder *folder = NULL;
558 TnyHeader *header = NULL;
559 ModestMailOperationPrivate *priv = NULL;
561 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
562 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
564 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
566 /* Get account and set it into mail_operation */
567 priv->account = g_object_ref (transport_account);
569 if (html_body == NULL) {
570 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
572 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
575 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
576 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
577 "modest: failed to create a new msg\n");
581 /* add priority flags */
582 header = tny_msg_get_header (msg);
583 tny_header_set_flags (header, priority_flags);
585 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
587 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
588 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
589 "modest: failed to create a new msg\n");
593 if (draft_msg != NULL) {
594 header = tny_msg_get_header (draft_msg);
595 tny_folder_remove_msg (folder, header, NULL);
596 g_object_unref (header);
599 tny_folder_add_msg (folder, msg, &(priv->error));
605 g_object_unref (G_OBJECT(msg));
607 g_object_unref (G_OBJECT(folder));
609 modest_mail_operation_notify_end (self);
614 ModestMailOperation *mail_op;
615 TnyStoreAccount *account;
616 TnyTransportAccount *transport_account;
619 gchar *retrieve_type;
622 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
623 /* We use this folder observer to track the headers that have been
624 * added to a folder */
627 TnyList *new_headers;
628 } InternalFolderObserver;
632 } InternalFolderObserverClass;
634 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
636 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
637 internal_folder_observer,
639 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
643 foreach_add_item (gpointer header, gpointer user_data)
645 /* printf("DEBUG: %s: header subject=%s\n",
646 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
648 tny_list_prepend (TNY_LIST (user_data),
649 g_object_ref (G_OBJECT (header)));
652 /* This is the method that looks for new messages in a folder */
654 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
656 InternalFolderObserver *derived = (InternalFolderObserver *)self;
658 TnyFolderChangeChanged changed;
660 changed = tny_folder_change_get_changed (change);
662 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
665 /* Get added headers */
666 list = tny_simple_list_new ();
667 tny_folder_change_get_added_headers (change, list);
669 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
670 * __FUNCTION__, tny_list_get_length(list));
673 /* Add them to the folder observer */
674 tny_list_foreach (list, foreach_add_item,
675 derived->new_headers);
677 g_object_unref (G_OBJECT (list));
682 internal_folder_observer_init (InternalFolderObserver *self)
684 self->new_headers = tny_simple_list_new ();
687 internal_folder_observer_finalize (GObject *object)
689 InternalFolderObserver *self;
691 self = (InternalFolderObserver *) object;
692 g_object_unref (self->new_headers);
694 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
697 tny_folder_observer_init (TnyFolderObserverIface *iface)
699 iface->update_func = internal_folder_observer_update;
702 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
704 GObjectClass *object_class;
706 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
707 object_class = (GObjectClass*) klass;
708 object_class->finalize = internal_folder_observer_finalize;
714 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
717 TnyList *folders = tny_simple_list_new ();
719 tny_folder_store_get_folders (store, folders, query, NULL);
720 iter = tny_list_create_iterator (folders);
722 while (!tny_iterator_is_done (iter)) {
724 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
726 tny_list_prepend (all_folders, G_OBJECT (folder));
727 recurse_folders (folder, query, all_folders);
728 g_object_unref (G_OBJECT (folder));
730 tny_iterator_next (iter);
732 g_object_unref (G_OBJECT (iter));
733 g_object_unref (G_OBJECT (folders));
737 * Issues the "progress-changed" signal. The timer won't be removed,
738 * so you must call g_source_remove to stop the signal emission
741 idle_notify_progress (gpointer data)
743 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
744 ModestMailOperationState *state;
746 state = modest_mail_operation_clone_state (mail_op);
747 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
748 g_slice_free (ModestMailOperationState, state);
754 * Issues the "progress-changed" signal and removes the timer. It uses
755 * a lock to ensure that the progress information of the mail
756 * operation is not modified while there are notifications pending
759 idle_notify_progress_once (gpointer data)
763 pair = (ModestPair *) data;
765 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
767 /* Free the state and the reference to the mail operation */
768 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
769 g_object_unref (pair->first);
775 * Used by update_account_thread to notify the queue from the main
776 * loop. We call it inside an idle call to achieve that
779 notify_update_account_queue (gpointer data)
781 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
782 ModestMailOperationPrivate *priv = NULL;
784 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
786 modest_mail_operation_notify_end (mail_op);
787 g_object_unref (mail_op);
793 compare_headers_by_date (gconstpointer a,
796 TnyHeader **header1, **header2;
799 header1 = (TnyHeader **) a;
800 header2 = (TnyHeader **) b;
802 sent1 = tny_header_get_date_sent (*header1);
803 sent2 = tny_header_get_date_sent (*header2);
805 /* We want the most recent ones (greater time_t) at the
814 set_last_updated_idle (gpointer data)
816 /* It does not matter if the time is not exactly the same than
817 the time when this idle was called, it's just an
818 approximation and it won't be very different */
819 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
821 MODEST_ACCOUNT_LAST_UPDATED,
829 update_account_thread (gpointer thr_user_data)
831 UpdateAccountInfo *info;
832 TnyList *all_folders = NULL;
833 GPtrArray *new_headers;
834 TnyIterator *iter = NULL;
835 TnyFolderStoreQuery *query = NULL;
836 ModestMailOperationPrivate *priv;
837 ModestTnySendQueue *send_queue;
840 info = (UpdateAccountInfo *) thr_user_data;
841 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
843 /* Get account and set it into mail_operation */
844 priv->account = g_object_ref (info->account);
847 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
848 * show any updates unless we do that
850 if (TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
851 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
853 /* Get all the folders. We can do it synchronously because
854 we're already running in a different thread than the UI */
855 all_folders = tny_simple_list_new ();
856 query = tny_folder_store_query_new ();
857 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
858 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
863 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
867 iter = tny_list_create_iterator (all_folders);
868 while (!tny_iterator_is_done (iter)) {
869 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
871 recurse_folders (folder, query, all_folders);
872 tny_iterator_next (iter);
874 g_object_unref (G_OBJECT (iter));
876 /* Update status and notify. We need to call the notification
877 with a source function in order to call it from the main
878 loop. We need that in order not to get into trouble with
879 Gtk+. We use a timeout in order to provide more status
880 information, because the sync tinymail call does not
881 provide it for the moment */
882 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
884 /* Refresh folders */
885 new_headers = g_ptr_array_new ();
886 iter = tny_list_create_iterator (all_folders);
888 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
890 InternalFolderObserver *observer;
891 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
893 /* Refresh the folder */
894 /* Our observer receives notification of new emails during folder refreshes,
895 * so we can use observer->new_headers.
896 * TODO: This does not seem to be providing accurate numbers.
897 * Possibly the observer is notified asynchronously.
899 observer = g_object_new (internal_folder_observer_get_type (), NULL);
900 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
902 /* This gets the status information (headers) from the server.
903 * We use the blocking version, because we are already in a separate
907 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
908 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
911 /* If the retrieve type is full messages, refresh and get the messages */
912 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
914 iter = tny_list_create_iterator (observer->new_headers);
915 while (!tny_iterator_is_done (iter)) {
916 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
917 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
918 * __FUNCTION__, tny_account_get_id (priv->account),
919 * tny_header_get_subject (header));
922 /* Apply per-message size limits */
923 if (tny_header_get_message_size (header) < info->max_size)
924 g_ptr_array_add (new_headers, g_object_ref (header));
926 g_object_unref (header);
927 tny_iterator_next (iter);
929 g_object_unref (iter);
930 } else /* If it's headers only, then just poke the folder status (this will update the unread and
931 * total count of folder observers, like the folder list model*/
932 tny_folder_poke_status (TNY_FOLDER (folder));
934 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
935 g_object_unref (observer);
939 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
941 g_object_unref (G_OBJECT (folder));
942 tny_iterator_next (iter);
945 did_a_cancel = FALSE;
947 g_object_unref (G_OBJECT (iter));
948 g_source_remove (timeout);
950 if (new_headers->len > 0) {
954 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
956 /* Apply message count limit */
957 /* If the number of messages exceeds the maximum, ask the
958 * user to download them all,
959 * as per the UI spec "Retrieval Limits" section in 4.4:
961 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
962 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
963 if (new_headers->len > info->retrieve_limit) {
964 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
965 * with 'Get all' and 'Newest only' buttons. */
966 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
967 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
968 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
969 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
970 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
975 priv->total = MIN (new_headers->len, info->retrieve_limit);
976 while (msg_num < priv->total) {
978 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
979 TnyFolder *folder = tny_header_get_folder (header);
980 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
981 ModestMailOperationState *state;
985 /* We can not just use the mail operation because the
986 values of done and total could change before the
988 state = modest_mail_operation_clone_state (info->mail_op);
989 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
990 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
991 pair, (GDestroyNotify) modest_pair_free);
993 g_object_unref (msg);
994 g_object_unref (folder);
998 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
999 g_ptr_array_free (new_headers, FALSE);
1003 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1006 if (priv->account != NULL)
1007 g_object_unref (priv->account);
1008 priv->account = g_object_ref (info->transport_account);
1010 send_queue = modest_runtime_get_send_queue (info->transport_account);
1012 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
1013 modest_tny_send_queue_try_to_send (send_queue);
1014 g_source_remove (timeout);
1016 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1017 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1018 "cannot create a send queue for %s\n",
1019 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1020 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1023 /* Check if the operation was a success */
1025 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1027 /* Update the last updated key */
1028 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1029 set_last_updated_idle,
1030 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1031 (GDestroyNotify) g_free);
1035 /* Notify about operation end. Note that the info could be
1036 freed before this idle happens, but the mail operation will
1038 g_idle_add (notify_update_account_queue, info->mail_op);
1041 g_object_unref (query);
1042 g_object_unref (all_folders);
1043 g_object_unref (info->account);
1044 g_object_unref (info->transport_account);
1045 g_free (info->retrieve_type);
1046 g_slice_free (UpdateAccountInfo, info);
1052 modest_mail_operation_update_account (ModestMailOperation *self,
1053 const gchar *account_name)
1056 UpdateAccountInfo *info;
1057 ModestMailOperationPrivate *priv;
1058 ModestAccountMgr *mgr;
1059 TnyStoreAccount *modest_account;
1060 TnyTransportAccount *transport_account;
1062 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1063 g_return_val_if_fail (account_name, FALSE);
1065 /* Make sure that we have a connection, and request one
1067 * TODO: Is there some way to trigger this for every attempt to
1068 * use the network? */
1069 if (!modest_platform_connect_and_wait(NULL))
1072 /* Init mail operation. Set total and done to 0, and do not
1073 update them, this way the progress objects will know that
1074 we have no clue about the number of the objects */
1075 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1078 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1080 /* Get the Modest account */
1081 modest_account = (TnyStoreAccount *)
1082 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1084 TNY_ACCOUNT_TYPE_STORE);
1086 if (!modest_account) {
1087 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1088 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1089 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1090 "cannot get tny store account for %s\n", account_name);
1091 modest_mail_operation_notify_end (self);
1097 /* Get the transport account, we can not do it in the thread
1098 due to some problems with dbus */
1099 transport_account = (TnyTransportAccount *)
1100 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1102 if (!transport_account) {
1103 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1104 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1105 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1106 "cannot get tny transport account for %s\n", account_name);
1107 modest_mail_operation_notify_end (self);
1112 /* Create the helper object */
1113 info = g_slice_new (UpdateAccountInfo);
1114 info->mail_op = self;
1115 info->account = modest_account;
1116 info->transport_account = transport_account;
1118 /* Get the message size limit */
1119 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1120 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1121 if (info->max_size == 0)
1122 info->max_size = G_MAXINT;
1124 info->max_size = info->max_size * KB;
1126 /* Get per-account retrieval type */
1127 mgr = modest_runtime_get_account_mgr ();
1128 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1129 MODEST_ACCOUNT_RETRIEVE, FALSE);
1131 /* Get per-account message amount retrieval limit */
1132 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1133 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1134 if (info->retrieve_limit == 0)
1135 info->retrieve_limit = G_MAXINT;
1137 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1139 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1144 /* ******************************************************************* */
1145 /* ************************** STORE ACTIONS ************************* */
1146 /* ******************************************************************* */
1150 modest_mail_operation_create_folder (ModestMailOperation *self,
1151 TnyFolderStore *parent,
1154 ModestMailOperationPrivate *priv;
1155 TnyFolder *new_folder = NULL;
1157 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1158 g_return_val_if_fail (name, NULL);
1160 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1163 if (TNY_IS_FOLDER (parent)) {
1164 /* Check folder rules */
1165 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1166 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1167 /* Set status failed and set an error */
1168 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1169 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1170 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1171 _("mail_in_ui_folder_create_error"));
1176 /* Create the folder */
1177 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1178 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1180 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1183 /* Notify about operation end */
1184 modest_mail_operation_notify_end (self);
1190 modest_mail_operation_remove_folder (ModestMailOperation *self,
1192 gboolean remove_to_trash)
1194 TnyAccount *account;
1195 ModestMailOperationPrivate *priv;
1196 ModestTnyFolderRules rules;
1198 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1199 g_return_if_fail (TNY_IS_FOLDER (folder));
1201 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1203 /* Check folder rules */
1204 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1205 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1206 /* Set status failed and set an error */
1207 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1208 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1209 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1210 _("mail_in_ui_folder_delete_error"));
1214 /* Get the account */
1215 account = modest_tny_folder_get_account (folder);
1216 priv->account = g_object_ref(account);
1218 /* Delete folder or move to trash */
1219 if (remove_to_trash) {
1220 TnyFolder *trash_folder = NULL;
1221 trash_folder = modest_tny_account_get_special_folder (account,
1222 TNY_FOLDER_TYPE_TRASH);
1223 /* TODO: error_handling */
1224 modest_mail_operation_xfer_folder (self, folder,
1225 TNY_FOLDER_STORE (trash_folder), TRUE);
1227 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1229 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1230 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1233 g_object_unref (G_OBJECT (parent));
1235 g_object_unref (G_OBJECT (account));
1238 /* Notify about operation end */
1239 modest_mail_operation_notify_end (self);
1243 transfer_folder_status_cb (GObject *obj,
1247 ModestMailOperation *self;
1248 ModestMailOperationPrivate *priv;
1249 ModestMailOperationState *state;
1251 g_return_if_fail (status != NULL);
1252 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1254 self = MODEST_MAIL_OPERATION (user_data);
1255 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1257 if ((status->position == 1) && (status->of_total == 100))
1260 priv->done = status->position;
1261 priv->total = status->of_total;
1263 state = modest_mail_operation_clone_state (self);
1264 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1265 g_slice_free (ModestMailOperationState, state);
1270 transfer_folder_cb (TnyFolder *folder,
1271 TnyFolderStore *into,
1273 TnyFolder *new_folder, GError **err,
1276 ModestMailOperation *self = NULL;
1277 ModestMailOperationPrivate *priv = NULL;
1279 self = MODEST_MAIL_OPERATION (user_data);
1281 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1284 priv->error = g_error_copy (*err);
1286 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1287 } else if (cancelled) {
1288 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1289 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1290 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1291 _("Transference of %s was cancelled."),
1292 tny_folder_get_name (folder));
1295 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1299 g_object_unref (folder);
1300 g_object_unref (into);
1301 if (new_folder != NULL)
1302 g_object_unref (new_folder);
1304 /* Notify about operation end */
1305 modest_mail_operation_notify_end (self);
1309 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1311 TnyFolderStore *parent,
1312 gboolean delete_original)
1314 ModestMailOperationPrivate *priv = NULL;
1315 ModestTnyFolderRules parent_rules, rules;
1317 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1318 g_return_if_fail (TNY_IS_FOLDER (folder));
1319 g_return_if_fail (TNY_IS_FOLDER (parent));
1321 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1323 /* Get account and set it into mail_operation */
1324 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1325 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1327 /* Get folder rules */
1328 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1329 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1331 if (!TNY_IS_FOLDER_STORE (parent)) {
1335 /* The moveable restriction is applied also to copy operation */
1336 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1337 /* Set status failed and set an error */
1338 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1339 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1340 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1341 _("mail_in_ui_folder_move_target_error"));
1343 /* Notify the queue */
1344 modest_mail_operation_notify_end (self);
1345 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1346 /* Set status failed and set an error */
1347 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1348 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1349 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1350 _("FIXME: parent folder does not accept new folders"));
1352 /* Notify the queue */
1353 modest_mail_operation_notify_end (self);
1355 /* Pick references for async calls */
1356 g_object_ref (folder);
1357 g_object_ref (parent);
1359 /* Move/Copy folder */
1360 tny_folder_copy_async (folder,
1362 tny_folder_get_name (folder),
1365 transfer_folder_status_cb,
1371 modest_mail_operation_rename_folder (ModestMailOperation *self,
1375 ModestMailOperationPrivate *priv;
1376 ModestTnyFolderRules rules;
1378 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1379 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1380 g_return_if_fail (name);
1382 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1384 /* Get account and set it into mail_operation */
1385 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1387 /* Check folder rules */
1388 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1389 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1390 /* Set status failed and set an error */
1391 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1392 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1393 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1394 _("FIXME: unable to rename"));
1396 /* Notify about operation end */
1397 modest_mail_operation_notify_end (self);
1399 /* Rename. Camel handles folder subscription/unsubscription */
1400 TnyFolderStore *into;
1402 into = tny_folder_get_folder_store (folder);
1403 tny_folder_copy_async (folder, into, name, TRUE,
1405 transfer_folder_status_cb,
1408 g_object_unref (into);
1413 /* ******************************************************************* */
1414 /* ************************** MSG ACTIONS ************************* */
1415 /* ******************************************************************* */
1417 void modest_mail_operation_get_msg (ModestMailOperation *self,
1419 GetMsgAsyncUserCallback user_callback,
1422 GetMsgAsyncHelper *helper = NULL;
1424 ModestMailOperationPrivate *priv;
1426 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1427 g_return_if_fail (TNY_IS_HEADER (header));
1429 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1430 folder = tny_header_get_folder (header);
1432 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1434 /* Get message from folder */
1436 /* Get account and set it into mail_operation */
1437 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1439 helper = g_slice_new0 (GetMsgAsyncHelper);
1440 helper->mail_op = self;
1441 helper->user_callback = user_callback;
1442 helper->pending_ops = 1;
1443 helper->user_data = user_data;
1445 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1447 g_object_unref (G_OBJECT (folder));
1449 /* Set status failed and set an error */
1450 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1451 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1452 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1453 _("Error trying to get a message. No folder found for header"));
1455 /* Notify the queue */
1456 modest_mail_operation_notify_end (self);
1461 get_msg_cb (TnyFolder *folder,
1467 GetMsgAsyncHelper *helper = NULL;
1468 ModestMailOperation *self = NULL;
1469 ModestMailOperationPrivate *priv = NULL;
1471 helper = (GetMsgAsyncHelper *) user_data;
1472 g_return_if_fail (helper != NULL);
1473 self = helper->mail_op;
1474 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1475 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1477 helper->pending_ops--;
1479 /* Check errors and cancel */
1481 priv->error = g_error_copy (*error);
1482 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1486 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1487 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1488 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1489 _("Error trying to refresh the contents of %s"),
1490 tny_folder_get_name (folder));
1494 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1496 /* If user defined callback function was defined, call it */
1497 if (helper->user_callback) {
1498 helper->user_callback (self, NULL, msg, helper->user_data);
1503 if (helper->pending_ops == 0) {
1504 g_slice_free (GetMsgAsyncHelper, helper);
1506 /* Notify about operation end */
1507 modest_mail_operation_notify_end (self);
1512 get_msg_status_cb (GObject *obj,
1516 GetMsgAsyncHelper *helper = NULL;
1517 ModestMailOperation *self;
1518 ModestMailOperationPrivate *priv;
1519 ModestMailOperationState *state;
1521 g_return_if_fail (status != NULL);
1522 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1524 helper = (GetMsgAsyncHelper *) user_data;
1525 g_return_if_fail (helper != NULL);
1527 self = helper->mail_op;
1528 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1530 if ((status->position == 1) && (status->of_total == 100))
1536 state = modest_mail_operation_clone_state (self);
1537 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1538 g_slice_free (ModestMailOperationState, state);
1541 /****************************************************/
1543 ModestMailOperation *mail_op;
1545 GetMsgAsyncUserCallback user_callback;
1547 GDestroyNotify notify;
1551 GetMsgAsyncUserCallback user_callback;
1555 ModestMailOperation *mail_op;
1556 } NotifyGetMsgsInfo;
1560 * Used by get_msgs_full_thread to call the user_callback for each
1561 * message that has been read
1564 notify_get_msgs_full (gpointer data)
1566 NotifyGetMsgsInfo *info;
1568 info = (NotifyGetMsgsInfo *) data;
1570 /* Call the user callback */
1571 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1573 g_slice_free (NotifyGetMsgsInfo, info);
1579 * Used by get_msgs_full_thread to free al the thread resources and to
1580 * call the destroy function for the passed user_data
1583 get_msgs_full_destroyer (gpointer data)
1585 GetFullMsgsInfo *info;
1587 info = (GetFullMsgsInfo *) data;
1590 info->notify (info->user_data);
1593 g_object_unref (info->headers);
1594 g_slice_free (GetFullMsgsInfo, info);
1600 get_msgs_full_thread (gpointer thr_user_data)
1602 GetFullMsgsInfo *info;
1603 ModestMailOperationPrivate *priv = NULL;
1604 TnyIterator *iter = NULL;
1606 info = (GetFullMsgsInfo *) thr_user_data;
1607 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1609 iter = tny_list_create_iterator (info->headers);
1610 while (!tny_iterator_is_done (iter)) {
1614 header = TNY_HEADER (tny_iterator_get_current (iter));
1615 folder = tny_header_get_folder (header);
1617 /* Get message from folder */
1620 /* The callback will call it per each header */
1621 msg = tny_folder_get_msg (folder, header, &(priv->error));
1624 ModestMailOperationState *state;
1629 /* notify progress */
1630 state = modest_mail_operation_clone_state (info->mail_op);
1631 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1632 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1633 pair, (GDestroyNotify) modest_pair_free);
1635 /* The callback is the responsible for
1636 freeing the message */
1637 if (info->user_callback) {
1638 NotifyGetMsgsInfo *info_notify;
1639 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1640 info_notify->user_callback = info->user_callback;
1641 info_notify->mail_op = info->mail_op;
1642 info_notify->header = g_object_ref (header);
1643 info_notify->msg = g_object_ref (msg);
1644 info_notify->user_data = info->user_data;
1645 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1646 notify_get_msgs_full,
1649 g_object_unref (msg);
1652 /* Set status failed and set an error */
1653 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1654 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1655 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1656 "Error trying to get a message. No folder found for header");
1658 g_object_unref (header);
1659 tny_iterator_next (iter);
1662 /* Set operation status */
1663 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1664 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1666 /* Notify about operation end */
1667 g_idle_add (notify_update_account_queue, info->mail_op);
1669 /* Free thread resources. Will be called after all previous idles */
1670 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1676 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1677 TnyList *header_list,
1678 GetMsgAsyncUserCallback user_callback,
1680 GDestroyNotify notify)
1682 TnyHeader *header = NULL;
1683 TnyFolder *folder = NULL;
1685 ModestMailOperationPrivate *priv = NULL;
1686 GetFullMsgsInfo *info = NULL;
1687 gboolean size_ok = TRUE;
1689 TnyIterator *iter = NULL;
1691 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1693 /* Init mail operation */
1694 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1695 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1697 priv->total = tny_list_get_length(header_list);
1699 /* Get account and set it into mail_operation */
1700 if (tny_list_get_length (header_list) >= 1) {
1701 iter = tny_list_create_iterator (header_list);
1702 header = TNY_HEADER (tny_iterator_get_current (iter));
1703 folder = tny_header_get_folder (header);
1704 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1705 g_object_unref (header);
1706 g_object_unref (folder);
1708 if (tny_list_get_length (header_list) == 1) {
1709 g_object_unref (iter);
1714 /* Get msg size limit */
1715 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1716 MODEST_CONF_MSG_SIZE_LIMIT,
1719 g_clear_error (&(priv->error));
1720 max_size = G_MAXINT;
1722 max_size = max_size * KB;
1725 /* Check message size limits. If there is only one message
1726 always retrieve it */
1728 while (!tny_iterator_is_done (iter) && size_ok) {
1729 header = TNY_HEADER (tny_iterator_get_current (iter));
1730 if (tny_header_get_message_size (header) >= max_size)
1732 g_object_unref (header);
1733 tny_iterator_next (iter);
1735 g_object_unref (iter);
1739 /* Create the info */
1740 info = g_slice_new0 (GetFullMsgsInfo);
1741 info->mail_op = self;
1742 info->user_callback = user_callback;
1743 info->user_data = user_data;
1744 info->headers = g_object_ref (header_list);
1745 info->notify = notify;
1747 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1749 /* Set status failed and set an error */
1750 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1751 /* FIXME: the error msg is different for pop */
1752 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1753 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1754 _("emev_ni_ui_imap_msg_size_exceed_error"));
1755 /* Remove from queue and free resources */
1756 modest_mail_operation_notify_end (self);
1764 modest_mail_operation_remove_msg (ModestMailOperation *self,
1766 gboolean remove_to_trash)
1769 ModestMailOperationPrivate *priv;
1771 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1772 g_return_if_fail (TNY_IS_HEADER (header));
1774 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1775 folder = tny_header_get_folder (header);
1777 /* Get account and set it into mail_operation */
1778 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1780 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1782 /* Delete or move to trash */
1783 if (remove_to_trash) {
1784 TnyFolder *trash_folder;
1785 TnyStoreAccount *store_account;
1787 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1788 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1789 TNY_FOLDER_TYPE_TRASH);
1794 headers = tny_simple_list_new ();
1795 tny_list_append (headers, G_OBJECT (header));
1796 g_object_unref (header);
1799 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1800 g_object_unref (headers);
1801 /* g_object_unref (trash_folder); */
1803 ModestMailOperationPrivate *priv;
1805 /* Set status failed and set an error */
1806 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1807 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1808 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1809 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1810 _("Error trying to delete a message. Trash folder not found"));
1813 g_object_unref (G_OBJECT (store_account));
1815 tny_folder_remove_msg (folder, header, &(priv->error));
1817 tny_folder_sync(folder, TRUE, &(priv->error));
1822 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1824 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1827 g_object_unref (G_OBJECT (folder));
1829 /* Notify about operation end */
1830 modest_mail_operation_notify_end (self);
1834 transfer_msgs_status_cb (GObject *obj,
1838 XFerMsgAsyncHelper *helper = NULL;
1839 ModestMailOperation *self;
1840 ModestMailOperationPrivate *priv;
1841 ModestMailOperationState *state;
1844 g_return_if_fail (status != NULL);
1845 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1847 helper = (XFerMsgAsyncHelper *) user_data;
1848 g_return_if_fail (helper != NULL);
1850 self = helper->mail_op;
1851 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1853 if ((status->position == 1) && (status->of_total == 100))
1856 priv->done = status->position;
1857 priv->total = status->of_total;
1859 state = modest_mail_operation_clone_state (self);
1860 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1861 g_slice_free (ModestMailOperationState, state);
1866 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1868 XFerMsgAsyncHelper *helper;
1869 ModestMailOperation *self;
1870 ModestMailOperationPrivate *priv;
1872 helper = (XFerMsgAsyncHelper *) user_data;
1873 self = helper->mail_op;
1875 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1878 priv->error = g_error_copy (*err);
1880 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1881 } else if (cancelled) {
1882 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1883 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1884 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1885 _("Error trying to refresh the contents of %s"),
1886 tny_folder_get_name (folder));
1889 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1892 /* If user defined callback function was defined, call it */
1893 if (helper->user_callback) {
1894 helper->user_callback (priv->source, helper->user_data);
1898 g_object_unref (helper->headers);
1899 g_object_unref (helper->dest_folder);
1900 g_object_unref (helper->mail_op);
1901 g_slice_free (XFerMsgAsyncHelper, helper);
1902 g_object_unref (folder);
1904 /* Notify about operation end */
1905 modest_mail_operation_notify_end (self);
1909 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1912 gboolean delete_original,
1913 XferMsgsAsynUserCallback user_callback,
1916 ModestMailOperationPrivate *priv;
1918 TnyFolder *src_folder;
1919 XFerMsgAsyncHelper *helper;
1921 ModestTnyFolderRules rules;
1923 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1924 g_return_if_fail (TNY_IS_LIST (headers));
1925 g_return_if_fail (TNY_IS_FOLDER (folder));
1927 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1930 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1932 /* Apply folder rules */
1933 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1935 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1936 /* Set status failed and set an error */
1937 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1938 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1939 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1940 _("FIXME: folder does not accept msgs"));
1941 /* Notify the queue */
1942 modest_mail_operation_notify_end (self);
1946 /* Create the helper */
1947 helper = g_slice_new0 (XFerMsgAsyncHelper);
1948 helper->mail_op = g_object_ref(self);
1949 helper->dest_folder = g_object_ref(folder);
1950 helper->headers = g_object_ref(headers);
1951 helper->user_callback = user_callback;
1952 helper->user_data = user_data;
1954 /* Get source folder */
1955 iter = tny_list_create_iterator (headers);
1956 header = TNY_HEADER (tny_iterator_get_current (iter));
1957 src_folder = tny_header_get_folder (header);
1958 g_object_unref (header);
1959 g_object_unref (iter);
1961 /* Get account and set it into mail_operation */
1962 priv->account = modest_tny_folder_get_account (src_folder);
1964 /* Transfer messages */
1965 tny_folder_transfer_msgs_async (src_folder,
1970 transfer_msgs_status_cb,
1976 on_refresh_folder (TnyFolder *folder,
1981 ModestMailOperation *self;
1982 ModestMailOperationPrivate *priv;
1984 self = MODEST_MAIL_OPERATION (user_data);
1985 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1988 priv->error = g_error_copy (*error);
1989 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1994 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1995 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1996 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1997 _("Error trying to refresh the contents of %s"),
1998 tny_folder_get_name (folder));
2002 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2006 g_object_unref (folder);
2008 /* Notify about operation end */
2009 modest_mail_operation_notify_end (self);
2013 on_refresh_folder_status_update (GObject *obj,
2017 ModestMailOperation *self;
2018 ModestMailOperationPrivate *priv;
2019 ModestMailOperationState *state;
2021 g_return_if_fail (status != NULL);
2022 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2024 self = MODEST_MAIL_OPERATION (user_data);
2025 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2027 priv->done = status->position;
2028 priv->total = status->of_total;
2030 state = modest_mail_operation_clone_state (self);
2031 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2032 g_slice_free (ModestMailOperationState, state);
2036 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2039 ModestMailOperationPrivate *priv;
2041 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2043 /* Pick a reference */
2044 g_object_ref (folder);
2046 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2048 /* Get account and set it into mail_operation */
2049 priv->account = modest_tny_folder_get_account (folder);
2051 /* Refresh the folder. TODO: tinymail could issue a status
2052 updates before the callback call then this could happen. We
2053 must review the design */
2054 tny_folder_refresh_async (folder,
2056 on_refresh_folder_status_update,
2062 * It's used by the mail operation queue to notify the observers
2063 * attached to that signal that the operation finished. We need to use
2064 * that because tinymail does not give us the progress of a given
2065 * operation when it finishes (it directly calls the operation
2069 modest_mail_operation_notify_end (ModestMailOperation *self)
2071 ModestMailOperationState *state;
2073 /* Notify the observers about the mail opertation end */
2074 state = modest_mail_operation_clone_state (self);
2075 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2076 g_slice_free (ModestMailOperationState, state);