2 /* Copyright (c) 2006, Nokia Corporation
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of the Nokia Corporation nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <tny-mime-part.h>
34 #include <tny-store-account.h>
35 #include <tny-folder-store.h>
36 #include <tny-folder-store-query.h>
37 #include <tny-camel-stream.h>
38 #include <tny-camel-pop-store-account.h>
39 #include <tny-simple-list.h>
40 #include <tny-send-queue.h>
41 #include <tny-status.h>
42 #include <tny-folder-observer.h>
43 #include <camel/camel-stream-mem.h>
44 #include <glib/gi18n.h>
45 #include "modest-platform.h"
46 #include <modest-tny-account.h>
47 #include <modest-tny-send-queue.h>
48 #include <modest-runtime.h>
49 #include "modest-text-utils.h"
50 #include "modest-tny-msg.h"
51 #include "modest-tny-folder.h"
52 #include "modest-tny-platform-factory.h"
53 #include "modest-marshal.h"
54 #include "modest-error.h"
55 #include "modest-mail-operation.h"
59 /* 'private'/'protected' functions */
60 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
61 static void modest_mail_operation_init (ModestMailOperation *obj);
62 static void modest_mail_operation_finalize (GObject *obj);
64 static void get_msg_cb (TnyFolder *folder,
70 static void get_msg_status_cb (GObject *obj,
74 static void modest_mail_operation_notify_end (ModestMailOperation *self);
76 static gboolean did_a_cancel = FALSE;
78 enum _ModestMailOperationSignals
80 PROGRESS_CHANGED_SIGNAL,
85 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
86 struct _ModestMailOperationPrivate {
92 ErrorCheckingUserCallback error_checking;
93 gpointer error_checking_user_data;
94 ModestMailOperationStatus status;
95 ModestMailOperationTypeOperation op_type;
98 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
99 MODEST_TYPE_MAIL_OPERATION, \
100 ModestMailOperationPrivate))
102 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
103 priv->status = new_status;\
106 typedef struct _GetMsgAsyncHelper {
107 ModestMailOperation *mail_op;
108 GetMsgAsyncUserCallback user_callback;
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);
212 g_error_free (priv->error);
216 g_object_unref (priv->source);
220 g_object_unref (priv->account);
221 priv->account = NULL;
225 G_OBJECT_CLASS(parent_class)->finalize (obj);
229 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
232 ModestMailOperation *obj;
233 ModestMailOperationPrivate *priv;
235 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
236 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
238 priv->op_type = op_type;
240 priv->source = g_object_ref(source);
246 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
248 ErrorCheckingUserCallback error_handler,
251 ModestMailOperation *obj;
252 ModestMailOperationPrivate *priv;
254 obj = modest_mail_operation_new (op_type, source);
255 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
257 g_return_val_if_fail (error_handler != NULL, obj);
258 priv->error_checking = error_handler;
264 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
266 ModestMailOperationPrivate *priv;
268 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
269 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
271 if (priv->error_checking != NULL)
272 priv->error_checking (self, priv->error_checking_user_data);
276 ModestMailOperationTypeOperation
277 modest_mail_operation_get_type_operation (ModestMailOperation *self)
279 ModestMailOperationPrivate *priv;
281 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
283 return priv->op_type;
287 modest_mail_operation_is_mine (ModestMailOperation *self,
290 ModestMailOperationPrivate *priv;
292 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
293 if (priv->source == NULL) return FALSE;
295 return priv->source == me;
299 modest_mail_operation_get_source (ModestMailOperation *self)
301 ModestMailOperationPrivate *priv;
303 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
305 return g_object_ref (priv->source);
308 ModestMailOperationStatus
309 modest_mail_operation_get_status (ModestMailOperation *self)
311 ModestMailOperationPrivate *priv;
313 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
314 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
315 MODEST_MAIL_OPERATION_STATUS_INVALID);
317 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
322 modest_mail_operation_get_error (ModestMailOperation *self)
324 ModestMailOperationPrivate *priv;
326 g_return_val_if_fail (self, NULL);
327 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
329 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
334 modest_mail_operation_cancel (ModestMailOperation *self)
336 ModestMailOperationPrivate *priv;
338 if (!MODEST_IS_MAIL_OPERATION (self)) {
339 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
343 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
345 /* cancel current operation in account */
346 //tny_account_cancel (priv->account);
351 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
353 /* Notify about operation end */
354 modest_mail_operation_notify_end (self);
360 modest_mail_operation_get_task_done (ModestMailOperation *self)
362 ModestMailOperationPrivate *priv;
364 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
366 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
371 modest_mail_operation_get_task_total (ModestMailOperation *self)
373 ModestMailOperationPrivate *priv;
375 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
377 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
382 modest_mail_operation_is_finished (ModestMailOperation *self)
384 ModestMailOperationPrivate *priv;
385 gboolean retval = FALSE;
387 if (!MODEST_IS_MAIL_OPERATION (self)) {
388 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
392 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
394 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
395 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
396 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
397 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
407 modest_mail_operation_get_id (ModestMailOperation *self)
409 ModestMailOperationPrivate *priv;
411 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
413 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
418 modest_mail_operation_set_id (ModestMailOperation *self,
421 ModestMailOperationPrivate *priv;
423 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
425 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
430 * Creates an image of the current state of a mail operation, the
431 * caller must free it
433 static ModestMailOperationState *
434 modest_mail_operation_clone_state (ModestMailOperation *self)
436 ModestMailOperationState *state;
437 ModestMailOperationPrivate *priv;
439 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
441 state = g_slice_new (ModestMailOperationState);
443 state->status = priv->status;
444 state->op_type = priv->op_type;
445 state->done = priv->done;
446 state->total = priv->total;
447 state->finished = modest_mail_operation_is_finished (self);
452 /* ******************************************************************* */
453 /* ************************** SEND ACTIONS ************************* */
454 /* ******************************************************************* */
457 modest_mail_operation_send_mail (ModestMailOperation *self,
458 TnyTransportAccount *transport_account,
461 TnySendQueue *send_queue = NULL;
462 ModestMailOperationPrivate *priv;
464 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
465 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
466 g_return_if_fail (TNY_IS_MSG (msg));
468 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
470 /* Get account and set it into mail_operation */
471 priv->account = g_object_ref (transport_account);
473 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
474 if (!TNY_IS_SEND_QUEUE(send_queue)) {
475 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
476 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
477 "modest: could not find send queue for account\n");
479 tny_send_queue_add (send_queue, msg, &(priv->error));
482 /* Notify about operation end */
483 modest_mail_operation_notify_end (self);
487 modest_mail_operation_send_new_mail (ModestMailOperation *self,
488 TnyTransportAccount *transport_account,
490 const gchar *from, const gchar *to,
491 const gchar *cc, const gchar *bcc,
492 const gchar *subject, const gchar *plain_body,
493 const gchar *html_body,
494 const GList *attachments_list,
495 TnyHeaderFlags priority_flags)
497 TnyMsg *new_msg = NULL;
498 TnyFolder *folder = NULL;
499 TnyHeader *header = NULL;
500 ModestMailOperationPrivate *priv = NULL;
502 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
503 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
505 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
507 /* Get account and set it into mail_operation */
508 priv->account = g_object_ref (transport_account);
510 /* Check parametters */
512 /* Set status failed and set an error */
513 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
514 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
515 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
516 _("Error trying to send a mail. You need to set at least one recipient"));
520 if (html_body == NULL) {
521 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
523 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
526 g_printerr ("modest: failed to create a new msg\n");
530 /* Set priority flags in message */
531 header = tny_msg_get_header (new_msg);
532 if (priority_flags != 0)
533 tny_header_set_flags (header, priority_flags);
535 /* Call mail operation */
536 modest_mail_operation_send_mail (self, transport_account, new_msg);
538 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
540 if (draft_msg != NULL) {
541 header = tny_msg_get_header (draft_msg);
542 /* Note: This can fail (with a warning) if the message is not really already in a folder,
543 * because this function requires it to have a UID. */
544 tny_folder_remove_msg (folder, header, NULL);
545 g_object_unref (header);
550 g_object_unref (G_OBJECT (new_msg));
554 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
555 TnyTransportAccount *transport_account,
557 const gchar *from, const gchar *to,
558 const gchar *cc, const gchar *bcc,
559 const gchar *subject, const gchar *plain_body,
560 const gchar *html_body,
561 const GList *attachments_list,
562 TnyHeaderFlags priority_flags)
565 TnyFolder *folder = NULL;
566 TnyHeader *header = NULL;
567 ModestMailOperationPrivate *priv = NULL;
569 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
570 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
572 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
574 /* Get account and set it into mail_operation */
575 priv->account = g_object_ref (transport_account);
577 if (html_body == NULL) {
578 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
580 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
583 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
584 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
585 "modest: failed to create a new msg\n");
589 /* add priority flags */
590 header = tny_msg_get_header (msg);
591 tny_header_set_flags (header, priority_flags);
593 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
595 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
596 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
597 "modest: failed to create a new msg\n");
601 if (draft_msg != NULL) {
602 header = tny_msg_get_header (draft_msg);
603 tny_folder_remove_msg (folder, header, NULL);
604 g_object_unref (header);
607 tny_folder_add_msg (folder, msg, &(priv->error));
613 g_object_unref (G_OBJECT(msg));
615 g_object_unref (G_OBJECT(folder));
617 modest_mail_operation_notify_end (self);
622 ModestMailOperation *mail_op;
623 TnyStoreAccount *account;
624 TnyTransportAccount *transport_account;
627 gchar *retrieve_type;
630 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
631 /* We use this folder observer to track the headers that have been
632 * added to a folder */
635 TnyList *new_headers;
636 } InternalFolderObserver;
640 } InternalFolderObserverClass;
642 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
644 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
645 internal_folder_observer,
647 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
651 foreach_add_item (gpointer header, gpointer user_data)
653 /* printf("DEBUG: %s: header subject=%s\n",
654 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
656 tny_list_prepend (TNY_LIST (user_data),
657 g_object_ref (G_OBJECT (header)));
660 /* This is the method that looks for new messages in a folder */
662 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
664 InternalFolderObserver *derived = (InternalFolderObserver *)self;
666 TnyFolderChangeChanged changed;
668 changed = tny_folder_change_get_changed (change);
670 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
673 /* Get added headers */
674 list = tny_simple_list_new ();
675 tny_folder_change_get_added_headers (change, list);
677 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
678 * __FUNCTION__, tny_list_get_length(list));
681 /* Add them to the folder observer */
682 tny_list_foreach (list, foreach_add_item,
683 derived->new_headers);
685 g_object_unref (G_OBJECT (list));
690 internal_folder_observer_init (InternalFolderObserver *self)
692 self->new_headers = tny_simple_list_new ();
695 internal_folder_observer_finalize (GObject *object)
697 InternalFolderObserver *self;
699 self = (InternalFolderObserver *) object;
700 g_object_unref (self->new_headers);
702 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
705 tny_folder_observer_init (TnyFolderObserverIface *iface)
707 iface->update_func = internal_folder_observer_update;
710 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
712 GObjectClass *object_class;
714 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
715 object_class = (GObjectClass*) klass;
716 object_class->finalize = internal_folder_observer_finalize;
722 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
725 TnyList *folders = tny_simple_list_new ();
727 tny_folder_store_get_folders (store, folders, query, NULL);
728 iter = tny_list_create_iterator (folders);
730 while (!tny_iterator_is_done (iter)) {
732 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
734 tny_list_prepend (all_folders, G_OBJECT (folder));
735 recurse_folders (folder, query, all_folders);
736 g_object_unref (G_OBJECT (folder));
738 tny_iterator_next (iter);
740 g_object_unref (G_OBJECT (iter));
741 g_object_unref (G_OBJECT (folders));
745 * Issues the "progress-changed" signal. The timer won't be removed,
746 * so you must call g_source_remove to stop the signal emission
749 idle_notify_progress (gpointer data)
751 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
752 ModestMailOperationState *state;
754 state = modest_mail_operation_clone_state (mail_op);
755 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
756 g_slice_free (ModestMailOperationState, state);
762 * Issues the "progress-changed" signal and removes the timer. It uses
763 * a lock to ensure that the progress information of the mail
764 * operation is not modified while there are notifications pending
767 idle_notify_progress_once (gpointer data)
771 pair = (ModestPair *) data;
773 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
775 /* Free the state and the reference to the mail operation */
776 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
777 g_object_unref (pair->first);
783 * Used by update_account_thread to notify the queue from the main
784 * loop. We call it inside an idle call to achieve that
787 notify_update_account_queue (gpointer data)
789 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
790 ModestMailOperationPrivate *priv = NULL;
792 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
794 modest_mail_operation_notify_end (mail_op);
795 g_object_unref (mail_op);
801 compare_headers_by_date (gconstpointer a,
804 TnyHeader **header1, **header2;
807 header1 = (TnyHeader **) a;
808 header2 = (TnyHeader **) b;
810 sent1 = tny_header_get_date_sent (*header1);
811 sent2 = tny_header_get_date_sent (*header2);
813 /* We want the most recent ones (greater time_t) at the
822 set_last_updated_idle (gpointer data)
824 /* It does not matter if the time is not exactly the same than
825 the time when this idle was called, it's just an
826 approximation and it won't be very different */
827 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
829 MODEST_ACCOUNT_LAST_UPDATED,
837 update_account_thread (gpointer thr_user_data)
839 UpdateAccountInfo *info;
840 TnyList *all_folders = NULL;
841 GPtrArray *new_headers;
842 TnyIterator *iter = NULL;
843 TnyFolderStoreQuery *query = NULL;
844 ModestMailOperationPrivate *priv;
845 ModestTnySendQueue *send_queue;
847 info = (UpdateAccountInfo *) thr_user_data;
848 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
850 /* Get account and set it into mail_operation */
851 priv->account = g_object_ref (info->account);
854 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
855 * show any updates unless we do that
857 if (TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
858 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
860 /* Get all the folders. We can do it synchronously because
861 we're already running in a different thread than the UI */
862 all_folders = tny_simple_list_new ();
863 query = tny_folder_store_query_new ();
864 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
865 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
870 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
874 iter = tny_list_create_iterator (all_folders);
875 while (!tny_iterator_is_done (iter)) {
876 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
878 recurse_folders (folder, query, all_folders);
879 tny_iterator_next (iter);
881 g_object_unref (G_OBJECT (iter));
883 /* Update status and notify. We need to call the notification
884 with a source function in order to call it from the main
885 loop. We need that in order not to get into trouble with
886 Gtk+. We use a timeout in order to provide more status
887 information, because the sync tinymail call does not
888 provide it for the moment */
889 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
891 /* Refresh folders */
892 new_headers = g_ptr_array_new ();
893 iter = tny_list_create_iterator (all_folders);
895 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
897 InternalFolderObserver *observer;
898 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
900 /* Refresh the folder */
901 /* Our observer receives notification of new emails during folder refreshes,
902 * so we can use observer->new_headers.
903 * TODO: This does not seem to be providing accurate numbers.
904 * Possibly the observer is notified asynchronously.
906 observer = g_object_new (internal_folder_observer_get_type (), NULL);
907 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
909 /* This gets the status information (headers) from the server.
910 * We use the blocking version, because we are already in a separate
914 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
915 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
918 /* If the retrieve type is full messages, refresh and get the messages */
919 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
921 iter = tny_list_create_iterator (observer->new_headers);
922 while (!tny_iterator_is_done (iter)) {
923 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
924 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
925 * __FUNCTION__, tny_account_get_id (priv->account),
926 * tny_header_get_subject (header));
929 /* Apply per-message size limits */
930 if (tny_header_get_message_size (header) < info->max_size)
931 g_ptr_array_add (new_headers, g_object_ref (header));
933 g_object_unref (header);
934 tny_iterator_next (iter);
936 g_object_unref (iter);
939 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
940 g_object_unref (observer);
944 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
946 g_object_unref (G_OBJECT (folder));
947 tny_iterator_next (iter);
950 did_a_cancel = FALSE;
952 g_object_unref (G_OBJECT (iter));
953 g_source_remove (timeout);
955 if (new_headers->len > 0) {
959 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
961 /* Apply message count limit */
962 /* If the number of messages exceeds the maximum, ask the
963 * user to download them all,
964 * as per the UI spec "Retrieval Limits" section in 4.4:
966 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
967 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
968 if (new_headers->len > info->retrieve_limit) {
969 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
970 * with 'Get all' and 'Newest only' buttons. */
971 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
972 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
973 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
974 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
975 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
980 priv->total = MIN (new_headers->len, info->retrieve_limit);
981 while (msg_num < priv->total) {
983 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
984 TnyFolder *folder = tny_header_get_folder (header);
985 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
986 ModestMailOperationState *state;
990 /* We can not just use the mail operation because the
991 values of done and total could change before the
993 state = modest_mail_operation_clone_state (info->mail_op);
994 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
995 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
996 pair, (GDestroyNotify) modest_pair_free);
998 g_object_unref (msg);
999 g_object_unref (folder);
1003 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1004 g_ptr_array_free (new_headers, FALSE);
1008 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1011 if (priv->account != NULL)
1012 g_object_unref (priv->account);
1013 priv->account = g_object_ref (info->transport_account);
1015 send_queue = modest_runtime_get_send_queue (info->transport_account);
1017 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
1018 modest_tny_send_queue_try_to_send (send_queue);
1019 g_source_remove (timeout);
1021 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1022 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1023 "cannot create a send queue for %s\n",
1024 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1025 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1028 /* Check if the operation was a success */
1030 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1032 /* Update the last updated key */
1033 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1034 set_last_updated_idle,
1035 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1036 (GDestroyNotify) g_free);
1040 /* Notify about operation end. Note that the info could be
1041 freed before this idle happens, but the mail operation will
1043 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1046 g_object_unref (query);
1047 g_object_unref (all_folders);
1048 g_object_unref (info->account);
1049 g_object_unref (info->transport_account);
1050 g_free (info->retrieve_type);
1051 g_slice_free (UpdateAccountInfo, info);
1057 modest_mail_operation_update_account (ModestMailOperation *self,
1058 const gchar *account_name)
1061 UpdateAccountInfo *info;
1062 ModestMailOperationPrivate *priv;
1063 ModestAccountMgr *mgr;
1064 TnyStoreAccount *modest_account;
1065 TnyTransportAccount *transport_account;
1067 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1068 g_return_val_if_fail (account_name, FALSE);
1070 /* Make sure that we have a connection, and request one
1072 * TODO: Is there some way to trigger this for every attempt to
1073 * use the network? */
1074 if (!modest_platform_connect_and_wait(NULL))
1077 /* Init mail operation. Set total and done to 0, and do not
1078 update them, this way the progress objects will know that
1079 we have no clue about the number of the objects */
1080 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1083 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1085 /* Get the Modest account */
1086 modest_account = (TnyStoreAccount *)
1087 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1089 TNY_ACCOUNT_TYPE_STORE);
1091 if (!modest_account) {
1092 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1093 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1094 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1095 "cannot get tny store account for %s\n", account_name);
1096 modest_mail_operation_notify_end (self);
1102 /* Get the transport account, we can not do it in the thread
1103 due to some problems with dbus */
1104 transport_account = (TnyTransportAccount *)
1105 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1107 if (!transport_account) {
1108 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1109 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1110 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1111 "cannot get tny transport account for %s\n", account_name);
1112 modest_mail_operation_notify_end (self);
1117 /* Create the helper object */
1118 info = g_slice_new (UpdateAccountInfo);
1119 info->mail_op = self;
1120 info->account = modest_account;
1121 info->transport_account = transport_account;
1123 /* Get the message size limit */
1124 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1125 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1126 if (info->max_size == 0)
1127 info->max_size = G_MAXINT;
1129 info->max_size = info->max_size * KB;
1131 /* Get per-account retrieval type */
1132 mgr = modest_runtime_get_account_mgr ();
1133 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1134 MODEST_ACCOUNT_RETRIEVE, FALSE);
1136 /* Get per-account message amount retrieval limit */
1137 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1138 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1139 if (info->retrieve_limit == 0)
1140 info->retrieve_limit = G_MAXINT;
1142 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1144 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1149 /* ******************************************************************* */
1150 /* ************************** STORE ACTIONS ************************* */
1151 /* ******************************************************************* */
1155 modest_mail_operation_create_folder (ModestMailOperation *self,
1156 TnyFolderStore *parent,
1159 ModestMailOperationPrivate *priv;
1160 TnyFolder *new_folder = NULL;
1162 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1163 g_return_val_if_fail (name, NULL);
1165 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1168 if (TNY_IS_FOLDER (parent)) {
1169 /* Check folder rules */
1170 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1171 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1172 /* Set status failed and set an error */
1173 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1174 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1175 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1176 _("mail_in_ui_folder_create_error"));
1181 /* Create the folder */
1182 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1183 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1185 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1188 /* Notify about operation end */
1189 modest_mail_operation_notify_end (self);
1195 modest_mail_operation_remove_folder (ModestMailOperation *self,
1197 gboolean remove_to_trash)
1199 TnyAccount *account;
1200 ModestMailOperationPrivate *priv;
1201 ModestTnyFolderRules rules;
1203 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1204 g_return_if_fail (TNY_IS_FOLDER (folder));
1206 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1208 /* Check folder rules */
1209 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1210 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1211 /* Set status failed and set an error */
1212 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1213 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1214 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1215 _("mail_in_ui_folder_delete_error"));
1219 /* Get the account */
1220 account = modest_tny_folder_get_account (folder);
1221 priv->account = g_object_ref(account);
1223 /* Delete folder or move to trash */
1224 if (remove_to_trash) {
1225 TnyFolder *trash_folder = NULL;
1226 trash_folder = modest_tny_account_get_special_folder (account,
1227 TNY_FOLDER_TYPE_TRASH);
1228 /* TODO: error_handling */
1229 modest_mail_operation_xfer_folder (self, folder,
1230 TNY_FOLDER_STORE (trash_folder), TRUE);
1232 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1234 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1235 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1238 g_object_unref (G_OBJECT (parent));
1240 g_object_unref (G_OBJECT (account));
1243 /* Notify about operation end */
1244 modest_mail_operation_notify_end (self);
1248 transfer_folder_status_cb (GObject *obj,
1252 ModestMailOperation *self;
1253 ModestMailOperationPrivate *priv;
1254 ModestMailOperationState *state;
1256 g_return_if_fail (status != NULL);
1257 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1259 self = MODEST_MAIL_OPERATION (user_data);
1260 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1262 if ((status->position == 1) && (status->of_total == 100))
1265 priv->done = status->position;
1266 priv->total = status->of_total;
1268 state = modest_mail_operation_clone_state (self);
1269 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1270 g_slice_free (ModestMailOperationState, state);
1275 transfer_folder_cb (TnyFolder *folder,
1276 TnyFolderStore *into,
1278 TnyFolder *new_folder, GError **err,
1281 ModestMailOperation *self = NULL;
1282 ModestMailOperationPrivate *priv = NULL;
1284 self = MODEST_MAIL_OPERATION (user_data);
1286 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1289 priv->error = g_error_copy (*err);
1291 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1292 } else if (cancelled) {
1293 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1294 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1295 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1296 _("Transference of %s was cancelled."),
1297 tny_folder_get_name (folder));
1300 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1304 g_object_unref (folder);
1305 g_object_unref (into);
1306 if (new_folder != NULL)
1307 g_object_unref (new_folder);
1309 /* Notify about operation end */
1310 modest_mail_operation_notify_end (self);
1314 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1316 TnyFolderStore *parent,
1317 gboolean delete_original)
1319 ModestMailOperationPrivate *priv = NULL;
1320 ModestTnyFolderRules parent_rules, rules;
1322 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1323 g_return_if_fail (TNY_IS_FOLDER (folder));
1324 g_return_if_fail (TNY_IS_FOLDER (parent));
1326 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1328 /* Get account and set it into mail_operation */
1329 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1330 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1332 /* Get folder rules */
1333 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1334 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1336 if (!TNY_IS_FOLDER_STORE (parent)) {
1340 /* The moveable restriction is applied also to copy operation */
1341 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1342 /* Set status failed and set an error */
1343 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1344 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1345 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1346 _("mail_in_ui_folder_move_target_error"));
1348 /* Notify the queue */
1349 modest_mail_operation_notify_end (self);
1350 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1351 /* Set status failed and set an error */
1352 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1353 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1354 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1355 _("FIXME: parent folder does not accept new folders"));
1357 /* Notify the queue */
1358 modest_mail_operation_notify_end (self);
1360 /* Pick references for async calls */
1361 g_object_ref (folder);
1362 g_object_ref (parent);
1364 /* Move/Copy folder */
1365 tny_folder_copy_async (folder,
1367 tny_folder_get_name (folder),
1370 transfer_folder_status_cb,
1376 modest_mail_operation_rename_folder (ModestMailOperation *self,
1380 ModestMailOperationPrivate *priv;
1381 ModestTnyFolderRules rules;
1383 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1384 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1385 g_return_if_fail (name);
1387 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1389 /* Get account and set it into mail_operation */
1390 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1392 /* Check folder rules */
1393 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1394 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1395 /* Set status failed and set an error */
1396 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1397 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1398 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1399 _("FIXME: unable to rename"));
1401 /* Notify about operation end */
1402 modest_mail_operation_notify_end (self);
1404 /* Rename. Camel handles folder subscription/unsubscription */
1405 TnyFolderStore *into;
1407 into = tny_folder_get_folder_store (folder);
1408 tny_folder_copy_async (folder, into, name, TRUE,
1410 transfer_folder_status_cb,
1413 g_object_unref (into);
1418 /* ******************************************************************* */
1419 /* ************************** MSG ACTIONS ************************* */
1420 /* ******************************************************************* */
1422 void modest_mail_operation_get_msg (ModestMailOperation *self,
1424 GetMsgAsyncUserCallback user_callback,
1427 GetMsgAsyncHelper *helper = NULL;
1429 ModestMailOperationPrivate *priv;
1431 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1432 g_return_if_fail (TNY_IS_HEADER (header));
1434 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1435 folder = tny_header_get_folder (header);
1437 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1439 /* Get message from folder */
1441 /* Get account and set it into mail_operation */
1442 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1444 helper = g_slice_new0 (GetMsgAsyncHelper);
1445 helper->mail_op = self;
1446 helper->user_callback = user_callback;
1447 helper->pending_ops = 1;
1448 helper->user_data = user_data;
1450 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1452 g_object_unref (G_OBJECT (folder));
1454 /* Set status failed and set an error */
1455 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1456 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1457 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1458 _("Error trying to get a message. No folder found for header"));
1460 /* Notify the queue */
1461 modest_mail_operation_notify_end (self);
1466 get_msg_cb (TnyFolder *folder,
1472 GetMsgAsyncHelper *helper = NULL;
1473 ModestMailOperation *self = NULL;
1474 ModestMailOperationPrivate *priv = NULL;
1476 helper = (GetMsgAsyncHelper *) user_data;
1477 g_return_if_fail (helper != NULL);
1478 self = helper->mail_op;
1479 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1480 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1482 helper->pending_ops--;
1484 /* Check errors and cancel */
1486 priv->error = g_error_copy (*error);
1487 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1491 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1492 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1493 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1494 _("Error trying to refresh the contents of %s"),
1495 tny_folder_get_name (folder));
1499 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1501 /* If user defined callback function was defined, call it */
1502 if (helper->user_callback) {
1503 helper->user_callback (self, NULL, msg, helper->user_data);
1508 if (helper->pending_ops == 0) {
1509 g_slice_free (GetMsgAsyncHelper, helper);
1511 /* Notify about operation end */
1512 modest_mail_operation_notify_end (self);
1517 get_msg_status_cb (GObject *obj,
1521 GetMsgAsyncHelper *helper = NULL;
1522 ModestMailOperation *self;
1523 ModestMailOperationPrivate *priv;
1524 ModestMailOperationState *state;
1526 g_return_if_fail (status != NULL);
1527 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1529 helper = (GetMsgAsyncHelper *) user_data;
1530 g_return_if_fail (helper != NULL);
1532 self = helper->mail_op;
1533 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1535 if ((status->position == 1) && (status->of_total == 100))
1541 state = modest_mail_operation_clone_state (self);
1542 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1543 g_slice_free (ModestMailOperationState, state);
1546 /****************************************************/
1548 ModestMailOperation *mail_op;
1550 GetMsgAsyncUserCallback user_callback;
1552 GDestroyNotify notify;
1556 GetMsgAsyncUserCallback user_callback;
1560 ModestMailOperation *mail_op;
1561 } NotifyGetMsgsInfo;
1565 * Used by get_msgs_full_thread to call the user_callback for each
1566 * message that has been read
1569 notify_get_msgs_full (gpointer data)
1571 NotifyGetMsgsInfo *info;
1573 info = (NotifyGetMsgsInfo *) data;
1575 /* Call the user callback */
1576 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1578 g_slice_free (NotifyGetMsgsInfo, info);
1584 * Used by get_msgs_full_thread to free al the thread resources and to
1585 * call the destroy function for the passed user_data
1588 get_msgs_full_destroyer (gpointer data)
1590 GetFullMsgsInfo *info;
1592 info = (GetFullMsgsInfo *) data;
1595 info->notify (info->user_data);
1598 g_object_unref (info->headers);
1599 g_slice_free (GetFullMsgsInfo, info);
1605 get_msgs_full_thread (gpointer thr_user_data)
1607 GetFullMsgsInfo *info;
1608 ModestMailOperationPrivate *priv = NULL;
1609 TnyIterator *iter = NULL;
1611 info = (GetFullMsgsInfo *) thr_user_data;
1612 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1614 iter = tny_list_create_iterator (info->headers);
1615 while (!tny_iterator_is_done (iter)) {
1619 header = TNY_HEADER (tny_iterator_get_current (iter));
1620 folder = tny_header_get_folder (header);
1622 /* Get message from folder */
1625 /* The callback will call it per each header */
1626 msg = tny_folder_get_msg (folder, header, &(priv->error));
1629 ModestMailOperationState *state;
1634 /* notify progress */
1635 state = modest_mail_operation_clone_state (info->mail_op);
1636 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1637 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1638 pair, (GDestroyNotify) modest_pair_free);
1640 /* The callback is the responsible for
1641 freeing the message */
1642 if (info->user_callback) {
1643 NotifyGetMsgsInfo *info_notify;
1644 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1645 info_notify->user_callback = info->user_callback;
1646 info_notify->mail_op = info->mail_op;
1647 info_notify->header = g_object_ref (header);
1648 info_notify->msg = g_object_ref (msg);
1649 info_notify->user_data = info->user_data;
1650 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1651 notify_get_msgs_full,
1654 g_object_unref (msg);
1657 /* Set status failed and set an error */
1658 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1659 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1660 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1661 "Error trying to get a message. No folder found for header");
1663 g_object_unref (header);
1664 tny_iterator_next (iter);
1667 /* Set operation status */
1668 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1669 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1671 /* Notify about operation end */
1672 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1674 /* Free thread resources. Will be called after all previous idles */
1675 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1681 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1682 TnyList *header_list,
1683 GetMsgAsyncUserCallback user_callback,
1685 GDestroyNotify notify)
1687 TnyHeader *header = NULL;
1688 TnyFolder *folder = NULL;
1690 ModestMailOperationPrivate *priv = NULL;
1691 GetFullMsgsInfo *info = NULL;
1692 gboolean size_ok = TRUE;
1694 TnyIterator *iter = NULL;
1696 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1698 /* Init mail operation */
1699 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1700 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1702 priv->total = tny_list_get_length(header_list);
1704 /* Get account and set it into mail_operation */
1705 if (tny_list_get_length (header_list) >= 1) {
1706 iter = tny_list_create_iterator (header_list);
1707 header = TNY_HEADER (tny_iterator_get_current (iter));
1708 folder = tny_header_get_folder (header);
1709 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1710 g_object_unref (header);
1711 g_object_unref (folder);
1713 if (tny_list_get_length (header_list) == 1) {
1714 g_object_unref (iter);
1719 /* Get msg size limit */
1720 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1721 MODEST_CONF_MSG_SIZE_LIMIT,
1724 g_clear_error (&(priv->error));
1725 max_size = G_MAXINT;
1727 max_size = max_size * KB;
1730 /* Check message size limits. If there is only one message
1731 always retrieve it */
1733 while (!tny_iterator_is_done (iter) && size_ok) {
1734 header = TNY_HEADER (tny_iterator_get_current (iter));
1735 if (tny_header_get_message_size (header) >= max_size)
1737 g_object_unref (header);
1738 tny_iterator_next (iter);
1740 g_object_unref (iter);
1744 /* Create the info */
1745 info = g_slice_new0 (GetFullMsgsInfo);
1746 info->mail_op = self;
1747 info->user_callback = user_callback;
1748 info->user_data = user_data;
1749 info->headers = g_object_ref (header_list);
1750 info->notify = notify;
1752 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1754 /* Set status failed and set an error */
1755 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1756 /* FIXME: the error msg is different for pop */
1757 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1758 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1759 _("emev_ni_ui_imap_msg_size_exceed_error"));
1760 /* Remove from queue and free resources */
1761 modest_mail_operation_notify_end (self);
1769 modest_mail_operation_remove_msg (ModestMailOperation *self,
1771 gboolean remove_to_trash)
1774 ModestMailOperationPrivate *priv;
1776 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1777 g_return_if_fail (TNY_IS_HEADER (header));
1779 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1780 folder = tny_header_get_folder (header);
1782 /* Get account and set it into mail_operation */
1783 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1785 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1787 /* Delete or move to trash */
1788 if (remove_to_trash) {
1789 TnyFolder *trash_folder;
1790 TnyStoreAccount *store_account;
1792 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1793 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1794 TNY_FOLDER_TYPE_TRASH);
1799 headers = tny_simple_list_new ();
1800 tny_list_append (headers, G_OBJECT (header));
1801 g_object_unref (header);
1804 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1805 g_object_unref (headers);
1806 /* g_object_unref (trash_folder); */
1808 ModestMailOperationPrivate *priv;
1810 /* Set status failed and set an error */
1811 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1812 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1813 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1814 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1815 _("Error trying to delete a message. Trash folder not found"));
1818 g_object_unref (G_OBJECT (store_account));
1820 tny_folder_remove_msg (folder, header, &(priv->error));
1822 tny_folder_sync(folder, TRUE, &(priv->error));
1827 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1829 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1832 g_object_unref (G_OBJECT (folder));
1834 /* Notify about operation end */
1835 modest_mail_operation_notify_end (self);
1839 transfer_msgs_status_cb (GObject *obj,
1843 XFerMsgAsyncHelper *helper = NULL;
1844 ModestMailOperation *self;
1845 ModestMailOperationPrivate *priv;
1846 ModestMailOperationState *state;
1849 g_return_if_fail (status != NULL);
1850 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1852 helper = (XFerMsgAsyncHelper *) user_data;
1853 g_return_if_fail (helper != NULL);
1855 self = helper->mail_op;
1856 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1858 if ((status->position == 1) && (status->of_total == 100))
1861 priv->done = status->position;
1862 priv->total = status->of_total;
1864 state = modest_mail_operation_clone_state (self);
1865 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1866 g_slice_free (ModestMailOperationState, state);
1871 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1873 XFerMsgAsyncHelper *helper;
1874 ModestMailOperation *self;
1875 ModestMailOperationPrivate *priv;
1877 helper = (XFerMsgAsyncHelper *) user_data;
1878 self = helper->mail_op;
1880 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1883 priv->error = g_error_copy (*err);
1885 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1886 } else if (cancelled) {
1887 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1888 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1889 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1890 _("Error trying to refresh the contents of %s"),
1891 tny_folder_get_name (folder));
1894 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1897 /* If user defined callback function was defined, call it */
1898 if (helper->user_callback) {
1899 helper->user_callback (priv->source, helper->user_data);
1903 g_object_unref (helper->headers);
1904 g_object_unref (helper->dest_folder);
1905 g_object_unref (helper->mail_op);
1906 g_slice_free (XFerMsgAsyncHelper, helper);
1907 g_object_unref (folder);
1909 /* Notify about operation end */
1910 modest_mail_operation_notify_end (self);
1914 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1917 gboolean delete_original,
1918 XferMsgsAsynUserCallback user_callback,
1921 ModestMailOperationPrivate *priv;
1923 TnyFolder *src_folder;
1924 XFerMsgAsyncHelper *helper;
1926 ModestTnyFolderRules rules;
1928 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1929 g_return_if_fail (TNY_IS_LIST (headers));
1930 g_return_if_fail (TNY_IS_FOLDER (folder));
1932 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1935 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1937 /* Apply folder rules */
1938 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1940 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1941 /* Set status failed and set an error */
1942 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1943 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1944 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1945 _("FIXME: folder does not accept msgs"));
1946 /* Notify the queue */
1947 modest_mail_operation_notify_end (self);
1951 /* Create the helper */
1952 helper = g_slice_new0 (XFerMsgAsyncHelper);
1953 helper->mail_op = g_object_ref(self);
1954 helper->dest_folder = g_object_ref(folder);
1955 helper->headers = g_object_ref(headers);
1956 helper->user_callback = user_callback;
1957 helper->user_data = user_data;
1959 /* Get source folder */
1960 iter = tny_list_create_iterator (headers);
1961 header = TNY_HEADER (tny_iterator_get_current (iter));
1962 src_folder = tny_header_get_folder (header);
1963 g_object_unref (header);
1964 g_object_unref (iter);
1966 /* Get account and set it into mail_operation */
1967 priv->account = modest_tny_folder_get_account (src_folder);
1969 /* Transfer messages */
1970 tny_folder_transfer_msgs_async (src_folder,
1975 transfer_msgs_status_cb,
1981 on_refresh_folder (TnyFolder *folder,
1986 RefreshAsyncHelper *helper = NULL;
1987 ModestMailOperation *self = NULL;
1988 ModestMailOperationPrivate *priv = NULL;
1990 helper = (RefreshAsyncHelper *) user_data;
1991 self = helper->mail_op;
1992 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1995 priv->error = g_error_copy (*error);
1996 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2001 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2002 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2003 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2004 _("Error trying to refresh the contents of %s"),
2005 tny_folder_get_name (folder));
2009 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2012 /* Call user defined callback, if it exists */
2013 if (helper->user_callback)
2014 helper->user_callback (priv->source, folder, helper->user_data);
2017 g_object_unref (helper->mail_op);
2018 g_slice_free (RefreshAsyncHelper, helper);
2019 g_object_unref (folder);
2021 /* Notify about operation end */
2022 modest_mail_operation_notify_end (self);
2026 on_refresh_folder_status_update (GObject *obj,
2030 RefreshAsyncHelper *helper = NULL;
2031 ModestMailOperation *self = NULL;
2032 ModestMailOperationPrivate *priv = NULL;
2033 ModestMailOperationState *state;
2035 g_return_if_fail (user_data != NULL);
2036 g_return_if_fail (status != NULL);
2037 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2039 helper = (RefreshAsyncHelper *) user_data;
2040 self = helper->mail_op;
2041 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2043 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2045 priv->done = status->position;
2046 priv->total = status->of_total;
2048 state = modest_mail_operation_clone_state (self);
2049 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2050 g_slice_free (ModestMailOperationState, state);
2054 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2056 RefreshAsyncUserCallback user_callback,
2059 ModestMailOperationPrivate *priv = NULL;
2060 RefreshAsyncHelper *helper = NULL;
2062 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2064 /* Pick a reference */
2065 g_object_ref (folder);
2067 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2069 /* Get account and set it into mail_operation */
2070 priv->account = modest_tny_folder_get_account (folder);
2072 /* Create the helper */
2073 helper = g_slice_new0 (RefreshAsyncHelper);
2074 helper->mail_op = g_object_ref(self);
2075 helper->user_callback = user_callback;
2076 helper->user_data = user_data;
2078 /* Refresh the folder. TODO: tinymail could issue a status
2079 updates before the callback call then this could happen. We
2080 must review the design */
2081 tny_folder_refresh_async (folder,
2083 on_refresh_folder_status_update,
2089 * It's used by the mail operation queue to notify the observers
2090 * attached to that signal that the operation finished. We need to use
2091 * that because tinymail does not give us the progress of a given
2092 * operation when it finishes (it directly calls the operation
2096 modest_mail_operation_notify_end (ModestMailOperation *self)
2098 ModestMailOperationState *state;
2100 /* Notify the observers about the mail opertation end */
2101 state = modest_mail_operation_clone_state (self);
2102 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2103 g_slice_free (ModestMailOperationState, state);