1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-camel-pop-store-account.h>
38 #include <tny-simple-list.h>
39 #include <tny-send-queue.h>
40 #include <tny-status.h>
41 #include <tny-folder-observer.h>
42 #include <camel/camel-stream-mem.h>
43 #include <glib/gi18n.h>
44 #include "modest-platform.h"
45 #include <modest-tny-account.h>
46 #include <modest-tny-send-queue.h>
47 #include <modest-runtime.h>
48 #include "modest-text-utils.h"
49 #include "modest-tny-msg.h"
50 #include "modest-tny-folder.h"
51 #include "modest-tny-platform-factory.h"
52 #include "modest-marshal.h"
53 #include "modest-error.h"
54 #include "modest-mail-operation.h"
58 /* 'private'/'protected' functions */
59 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
60 static void modest_mail_operation_init (ModestMailOperation *obj);
61 static void modest_mail_operation_finalize (GObject *obj);
63 static void get_msg_cb (TnyFolder *folder,
69 static void get_msg_status_cb (GObject *obj,
73 static void modest_mail_operation_notify_end (ModestMailOperation *self);
75 static gboolean did_a_cancel = FALSE;
77 enum _ModestMailOperationSignals
79 PROGRESS_CHANGED_SIGNAL,
84 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
85 struct _ModestMailOperationPrivate {
92 ErrorCheckingUserCallback error_checking;
93 gpointer error_checking_user_data;
94 ModestMailOperationStatus status;
95 ModestMailOperationTypeOperation op_type;
98 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
99 MODEST_TYPE_MAIL_OPERATION, \
100 ModestMailOperationPrivate))
102 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
103 priv->status = new_status;\
106 typedef struct _GetMsgAsyncHelper {
107 ModestMailOperation *mail_op;
108 GetMsgAsyncUserCallback user_callback;
112 typedef struct _RefreshAsyncHelper {
113 ModestMailOperation *mail_op;
114 RefreshAsyncUserCallback user_callback;
116 } RefreshAsyncHelper;
118 typedef struct _XFerMsgAsyncHelper
120 ModestMailOperation *mail_op;
122 TnyFolder *dest_folder;
123 XferMsgsAsynUserCallback user_callback;
125 } XFerMsgAsyncHelper;
128 static GObjectClass *parent_class = NULL;
130 static guint signals[NUM_SIGNALS] = {0};
133 modest_mail_operation_get_type (void)
135 static GType my_type = 0;
137 static const GTypeInfo my_info = {
138 sizeof(ModestMailOperationClass),
139 NULL, /* base init */
140 NULL, /* base finalize */
141 (GClassInitFunc) modest_mail_operation_class_init,
142 NULL, /* class finalize */
143 NULL, /* class data */
144 sizeof(ModestMailOperation),
146 (GInstanceInitFunc) modest_mail_operation_init,
149 my_type = g_type_register_static (G_TYPE_OBJECT,
150 "ModestMailOperation",
157 modest_mail_operation_class_init (ModestMailOperationClass *klass)
159 GObjectClass *gobject_class;
160 gobject_class = (GObjectClass*) klass;
162 parent_class = g_type_class_peek_parent (klass);
163 gobject_class->finalize = modest_mail_operation_finalize;
165 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
168 * ModestMailOperation::progress-changed
169 * @self: the #MailOperation that emits the signal
170 * @user_data: user data set when the signal handler was connected
172 * Emitted when the progress of a mail operation changes
174 signals[PROGRESS_CHANGED_SIGNAL] =
175 g_signal_new ("progress-changed",
176 G_TYPE_FROM_CLASS (gobject_class),
178 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
180 g_cclosure_marshal_VOID__POINTER,
181 G_TYPE_NONE, 1, G_TYPE_POINTER);
186 modest_mail_operation_init (ModestMailOperation *obj)
188 ModestMailOperationPrivate *priv;
190 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
192 priv->account = NULL;
193 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
194 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
199 priv->error_checking = NULL;
200 priv->error_checking_user_data = NULL;
204 modest_mail_operation_finalize (GObject *obj)
206 ModestMailOperationPrivate *priv;
208 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
213 g_error_free (priv->error);
217 g_object_unref (priv->source);
221 g_object_unref (priv->account);
222 priv->account = NULL;
226 G_OBJECT_CLASS(parent_class)->finalize (obj);
230 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
233 ModestMailOperation *obj;
234 ModestMailOperationPrivate *priv;
236 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
237 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
239 priv->op_type = op_type;
241 priv->source = g_object_ref(source);
247 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
249 ErrorCheckingUserCallback error_handler,
252 ModestMailOperation *obj;
253 ModestMailOperationPrivate *priv;
255 obj = modest_mail_operation_new (op_type, source);
256 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
258 g_return_val_if_fail (error_handler != NULL, obj);
259 priv->error_checking = error_handler;
265 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
267 ModestMailOperationPrivate *priv;
269 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
270 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
272 if (priv->error_checking != NULL)
273 priv->error_checking (self, priv->error_checking_user_data);
277 ModestMailOperationTypeOperation
278 modest_mail_operation_get_type_operation (ModestMailOperation *self)
280 ModestMailOperationPrivate *priv;
282 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
284 return priv->op_type;
288 modest_mail_operation_is_mine (ModestMailOperation *self,
291 ModestMailOperationPrivate *priv;
293 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
294 if (priv->source == NULL) return FALSE;
296 return priv->source == me;
300 modest_mail_operation_get_source (ModestMailOperation *self)
302 ModestMailOperationPrivate *priv;
304 g_return_val_if_fail (self, NULL);
306 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
308 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
312 return g_object_ref (priv->source);
315 ModestMailOperationStatus
316 modest_mail_operation_get_status (ModestMailOperation *self)
318 ModestMailOperationPrivate *priv;
320 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
321 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
322 MODEST_MAIL_OPERATION_STATUS_INVALID);
324 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
326 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
327 return MODEST_MAIL_OPERATION_STATUS_INVALID;
334 modest_mail_operation_get_error (ModestMailOperation *self)
336 ModestMailOperationPrivate *priv;
338 g_return_val_if_fail (self, NULL);
339 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
341 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
344 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
352 modest_mail_operation_cancel (ModestMailOperation *self)
354 ModestMailOperationPrivate *priv;
356 if (!MODEST_IS_MAIL_OPERATION (self)) {
357 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
361 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
363 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
367 /* Notify about operation end */
368 modest_mail_operation_notify_end (self);
373 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
375 modest_mail_operation_queue_cancel_all (modest_runtime_get_mail_operation_queue());
382 modest_mail_operation_get_task_done (ModestMailOperation *self)
384 ModestMailOperationPrivate *priv;
386 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
388 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
393 modest_mail_operation_get_task_total (ModestMailOperation *self)
395 ModestMailOperationPrivate *priv;
397 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
399 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
404 modest_mail_operation_is_finished (ModestMailOperation *self)
406 ModestMailOperationPrivate *priv;
407 gboolean retval = FALSE;
409 if (!MODEST_IS_MAIL_OPERATION (self)) {
410 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
414 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
416 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
417 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
418 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
419 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
429 modest_mail_operation_get_id (ModestMailOperation *self)
431 ModestMailOperationPrivate *priv;
433 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
435 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
440 modest_mail_operation_set_id (ModestMailOperation *self,
443 ModestMailOperationPrivate *priv;
445 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
447 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
452 * Creates an image of the current state of a mail operation, the
453 * caller must free it
455 static ModestMailOperationState *
456 modest_mail_operation_clone_state (ModestMailOperation *self)
458 ModestMailOperationState *state;
459 ModestMailOperationPrivate *priv;
461 /* FIXME: this should be fixed properly
463 * in some cases, priv was NULL, so checking here to
466 g_return_val_if_fail (self, NULL);
467 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
468 g_return_val_if_fail (priv, NULL);
473 state = g_slice_new (ModestMailOperationState);
475 state->status = priv->status;
476 state->op_type = priv->op_type;
477 state->done = priv->done;
478 state->total = priv->total;
479 state->finished = modest_mail_operation_is_finished (self);
484 /* ******************************************************************* */
485 /* ************************** SEND ACTIONS ************************* */
486 /* ******************************************************************* */
489 modest_mail_operation_send_mail (ModestMailOperation *self,
490 TnyTransportAccount *transport_account,
493 TnySendQueue *send_queue = NULL;
494 ModestMailOperationPrivate *priv;
496 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
497 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
498 g_return_if_fail (TNY_IS_MSG (msg));
500 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
502 /* Get account and set it into mail_operation */
503 priv->account = g_object_ref (transport_account);
505 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
506 if (!TNY_IS_SEND_QUEUE(send_queue)) {
507 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
508 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
509 "modest: could not find send queue for account\n");
511 tny_send_queue_add (send_queue, msg, &(priv->error));
514 /* Notify about operation end */
515 modest_mail_operation_notify_end (self);
519 modest_mail_operation_send_new_mail (ModestMailOperation *self,
520 TnyTransportAccount *transport_account,
522 const gchar *from, const gchar *to,
523 const gchar *cc, const gchar *bcc,
524 const gchar *subject, const gchar *plain_body,
525 const gchar *html_body,
526 const GList *attachments_list,
527 TnyHeaderFlags priority_flags)
529 TnyMsg *new_msg = NULL;
530 TnyFolder *folder = NULL;
531 TnyHeader *header = NULL;
532 ModestMailOperationPrivate *priv = NULL;
534 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
535 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
537 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
539 /* Get account and set it into mail_operation */
540 priv->account = g_object_ref (transport_account);
542 /* Check parametters */
544 /* Set status failed and set an error */
545 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
546 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
547 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
548 _("Error trying to send a mail. You need to set at least one recipient"));
552 if (html_body == NULL) {
553 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
555 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
558 g_printerr ("modest: failed to create a new msg\n");
562 /* Set priority flags in message */
563 header = tny_msg_get_header (new_msg);
564 if (priority_flags != 0)
565 tny_header_set_flags (header, priority_flags);
567 /* Call mail operation */
568 modest_mail_operation_send_mail (self, transport_account, new_msg);
570 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
572 if (draft_msg != NULL) {
573 header = tny_msg_get_header (draft_msg);
574 /* Note: This can fail (with a warning) if the message is not really already in a folder,
575 * because this function requires it to have a UID. */
576 tny_folder_remove_msg (folder, header, NULL);
577 g_object_unref (header);
582 g_object_unref (G_OBJECT (new_msg));
586 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
587 TnyTransportAccount *transport_account,
589 const gchar *from, const gchar *to,
590 const gchar *cc, const gchar *bcc,
591 const gchar *subject, const gchar *plain_body,
592 const gchar *html_body,
593 const GList *attachments_list,
594 TnyHeaderFlags priority_flags)
597 TnyFolder *folder = NULL;
598 TnyHeader *header = NULL;
599 ModestMailOperationPrivate *priv = NULL;
601 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
602 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
604 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
606 /* Get account and set it into mail_operation */
607 priv->account = g_object_ref (transport_account);
609 if (html_body == NULL) {
610 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
612 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
615 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
616 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
617 "modest: failed to create a new msg\n");
621 /* add priority flags */
622 header = tny_msg_get_header (msg);
623 tny_header_set_flags (header, priority_flags);
625 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
627 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
628 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
629 "modest: failed to create a new msg\n");
633 if (draft_msg != NULL) {
634 header = tny_msg_get_header (draft_msg);
635 /* Remove the old draft expunging it */
636 tny_folder_remove_msg (folder, header, NULL);
637 tny_folder_sync (folder, TRUE, NULL);
638 g_object_unref (header);
641 tny_folder_add_msg (folder, msg, &(priv->error));
647 g_object_unref (G_OBJECT(msg));
649 g_object_unref (G_OBJECT(folder));
651 modest_mail_operation_notify_end (self);
656 ModestMailOperation *mail_op;
657 TnyStoreAccount *account;
658 TnyTransportAccount *transport_account;
661 gchar *retrieve_type;
665 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
666 /* We use this folder observer to track the headers that have been
667 * added to a folder */
670 TnyList *new_headers;
671 } InternalFolderObserver;
675 } InternalFolderObserverClass;
677 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
679 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
680 internal_folder_observer,
682 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
686 foreach_add_item (gpointer header, gpointer user_data)
688 /* printf("DEBUG: %s: header subject=%s\n",
689 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
691 tny_list_prepend (TNY_LIST (user_data),
692 g_object_ref (G_OBJECT (header)));
695 /* This is the method that looks for new messages in a folder */
697 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
699 InternalFolderObserver *derived = (InternalFolderObserver *)self;
701 TnyFolderChangeChanged changed;
703 changed = tny_folder_change_get_changed (change);
705 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
708 /* Get added headers */
709 list = tny_simple_list_new ();
710 tny_folder_change_get_added_headers (change, list);
712 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
713 * __FUNCTION__, tny_list_get_length(list));
716 /* Add them to the folder observer */
717 tny_list_foreach (list, foreach_add_item,
718 derived->new_headers);
720 g_object_unref (G_OBJECT (list));
725 internal_folder_observer_init (InternalFolderObserver *self)
727 self->new_headers = tny_simple_list_new ();
730 internal_folder_observer_finalize (GObject *object)
732 InternalFolderObserver *self;
734 self = (InternalFolderObserver *) object;
735 g_object_unref (self->new_headers);
737 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
740 tny_folder_observer_init (TnyFolderObserverIface *iface)
742 iface->update_func = internal_folder_observer_update;
745 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
747 GObjectClass *object_class;
749 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
750 object_class = (GObjectClass*) klass;
751 object_class->finalize = internal_folder_observer_finalize;
757 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
760 TnyList *folders = tny_simple_list_new ();
762 tny_folder_store_get_folders (store, folders, query, NULL);
763 iter = tny_list_create_iterator (folders);
765 while (!tny_iterator_is_done (iter)) {
767 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
769 tny_list_prepend (all_folders, G_OBJECT (folder));
770 recurse_folders (folder, query, all_folders);
771 g_object_unref (G_OBJECT (folder));
773 tny_iterator_next (iter);
775 g_object_unref (G_OBJECT (iter));
776 g_object_unref (G_OBJECT (folders));
780 * Issues the "progress-changed" signal. The timer won't be removed,
781 * so you must call g_source_remove to stop the signal emission
784 idle_notify_progress (gpointer data)
786 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
787 ModestMailOperationState *state;
789 state = modest_mail_operation_clone_state (mail_op);
790 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
791 g_slice_free (ModestMailOperationState, state);
797 * Issues the "progress-changed" signal and removes the timer. It uses
798 * a lock to ensure that the progress information of the mail
799 * operation is not modified while there are notifications pending
802 idle_notify_progress_once (gpointer data)
806 pair = (ModestPair *) data;
808 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
810 /* Free the state and the reference to the mail operation */
811 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
812 g_object_unref (pair->first);
818 * Used by update_account_thread to notify the queue from the main
819 * loop. We call it inside an idle call to achieve that
822 notify_update_account_queue (gpointer data)
824 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
825 ModestMailOperationPrivate *priv = NULL;
827 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
829 modest_mail_operation_notify_end (mail_op);
830 g_object_unref (mail_op);
836 compare_headers_by_date (gconstpointer a,
839 TnyHeader **header1, **header2;
842 header1 = (TnyHeader **) a;
843 header2 = (TnyHeader **) b;
845 sent1 = tny_header_get_date_sent (*header1);
846 sent2 = tny_header_get_date_sent (*header2);
848 /* We want the most recent ones (greater time_t) at the
857 set_last_updated_idle (gpointer data)
859 /* It does not matter if the time is not exactly the same than
860 the time when this idle was called, it's just an
861 approximation and it won't be very different */
862 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
864 MODEST_ACCOUNT_LAST_UPDATED,
872 update_account_thread (gpointer thr_user_data)
874 static gboolean first_time = TRUE;
875 UpdateAccountInfo *info;
876 TnyList *all_folders = NULL;
877 GPtrArray *new_headers;
878 TnyIterator *iter = NULL;
879 TnyFolderStoreQuery *query = NULL;
880 ModestMailOperationPrivate *priv;
881 ModestTnySendQueue *send_queue;
883 info = (UpdateAccountInfo *) thr_user_data;
884 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
886 /* Get account and set it into mail_operation */
887 priv->account = g_object_ref (info->account);
890 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
891 * show any updates unless we do that
893 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
894 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
896 /* Get all the folders. We can do it synchronously because
897 we're already running in a different thread than the UI */
898 all_folders = tny_simple_list_new ();
899 query = tny_folder_store_query_new ();
900 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
901 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
906 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
910 iter = tny_list_create_iterator (all_folders);
911 while (!tny_iterator_is_done (iter)) {
912 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
914 recurse_folders (folder, query, all_folders);
915 tny_iterator_next (iter);
917 g_object_unref (G_OBJECT (iter));
919 /* Update status and notify. We need to call the notification
920 with a source function in order to call it from the main
921 loop. We need that in order not to get into trouble with
922 Gtk+. We use a timeout in order to provide more status
923 information, because the sync tinymail call does not
924 provide it for the moment */
925 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
927 /* Refresh folders */
928 new_headers = g_ptr_array_new ();
929 iter = tny_list_create_iterator (all_folders);
931 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
933 InternalFolderObserver *observer;
934 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
936 /* Refresh the folder */
937 /* Our observer receives notification of new emails during folder refreshes,
938 * so we can use observer->new_headers.
939 * TODO: This does not seem to be providing accurate numbers.
940 * Possibly the observer is notified asynchronously.
942 observer = g_object_new (internal_folder_observer_get_type (), NULL);
943 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
945 /* This gets the status information (headers) from the server.
946 * We use the blocking version, because we are already in a separate
950 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
951 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
954 /* If the retrieve type is full messages, refresh and get the messages */
955 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
957 iter = tny_list_create_iterator (observer->new_headers);
958 while (!tny_iterator_is_done (iter)) {
959 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
961 /* Apply per-message size limits */
962 if (tny_header_get_message_size (header) < info->max_size)
963 g_ptr_array_add (new_headers, g_object_ref (header));
965 g_object_unref (header);
966 tny_iterator_next (iter);
968 g_object_unref (iter);
970 /* We do not need to do it the first time
971 because it's automatically done by the tree
973 if (G_UNLIKELY (!first_time))
974 tny_folder_poke_status (TNY_FOLDER (folder));
976 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
977 g_object_unref (observer);
981 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
983 g_object_unref (G_OBJECT (folder));
984 tny_iterator_next (iter);
987 did_a_cancel = FALSE;
989 g_object_unref (G_OBJECT (iter));
990 g_source_remove (timeout);
992 if (new_headers->len > 0) {
996 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
998 /* Apply message count limit */
999 /* If the number of messages exceeds the maximum, ask the
1000 * user to download them all,
1001 * as per the UI spec "Retrieval Limits" section in 4.4:
1003 printf ("************************** DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
1004 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
1005 if (new_headers->len > info->retrieve_limit) {
1006 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
1007 * with 'Get all' and 'Newest only' buttons. */
1008 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1009 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1010 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1011 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1012 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1017 priv->total = MIN (new_headers->len, info->retrieve_limit);
1018 while (msg_num < priv->total) {
1020 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1021 TnyFolder *folder = tny_header_get_folder (header);
1022 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1023 ModestMailOperationState *state;
1027 /* We can not just use the mail operation because the
1028 values of done and total could change before the
1030 state = modest_mail_operation_clone_state (info->mail_op);
1031 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1032 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1033 pair, (GDestroyNotify) modest_pair_free);
1035 g_object_unref (msg);
1036 g_object_unref (folder);
1040 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1041 g_ptr_array_free (new_headers, FALSE);
1045 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1048 if (priv->account != NULL)
1049 g_object_unref (priv->account);
1050 priv->account = g_object_ref (info->transport_account);
1052 send_queue = modest_runtime_get_send_queue (info->transport_account);
1054 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
1055 modest_tny_send_queue_try_to_send (send_queue);
1056 g_source_remove (timeout);
1058 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1059 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1060 "cannot create a send queue for %s\n",
1061 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1062 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1065 /* Check if the operation was a success */
1067 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1069 /* Update the last updated key */
1070 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1071 set_last_updated_idle,
1072 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1073 (GDestroyNotify) g_free);
1077 /* Notify about operation end. Note that the info could be
1078 freed before this idle happens, but the mail operation will
1080 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1083 g_object_unref (query);
1084 g_object_unref (all_folders);
1085 g_object_unref (info->account);
1086 g_object_unref (info->transport_account);
1087 g_free (info->retrieve_type);
1088 g_slice_free (UpdateAccountInfo, info);
1096 modest_mail_operation_update_account (ModestMailOperation *self,
1097 const gchar *account_name)
1100 UpdateAccountInfo *info;
1101 ModestMailOperationPrivate *priv;
1102 ModestAccountMgr *mgr;
1103 TnyStoreAccount *modest_account;
1104 TnyTransportAccount *transport_account;
1106 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1107 g_return_val_if_fail (account_name, FALSE);
1109 /* Make sure that we have a connection, and request one
1111 * TODO: Is there some way to trigger this for every attempt to
1112 * use the network? */
1113 if (!modest_platform_connect_and_wait(NULL))
1116 /* Init mail operation. Set total and done to 0, and do not
1117 update them, this way the progress objects will know that
1118 we have no clue about the number of the objects */
1119 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1122 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1124 /* Get the Modest account */
1125 modest_account = (TnyStoreAccount *)
1126 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1128 TNY_ACCOUNT_TYPE_STORE);
1130 if (!modest_account) {
1131 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1132 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1133 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1134 "cannot get tny store account for %s\n", account_name);
1135 modest_mail_operation_notify_end (self);
1141 /* Get the transport account, we can not do it in the thread
1142 due to some problems with dbus */
1143 transport_account = (TnyTransportAccount *)
1144 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1146 if (!transport_account) {
1147 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1148 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1149 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1150 "cannot get tny transport account for %s\n", account_name);
1151 modest_mail_operation_notify_end (self);
1156 /* Create the helper object */
1157 info = g_slice_new (UpdateAccountInfo);
1158 info->mail_op = self;
1159 info->account = modest_account;
1160 info->transport_account = transport_account;
1162 /* Get the message size limit */
1163 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1164 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1165 if (info->max_size == 0)
1166 info->max_size = G_MAXINT;
1168 info->max_size = info->max_size * KB;
1170 /* Get per-account retrieval type */
1171 mgr = modest_runtime_get_account_mgr ();
1172 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1173 MODEST_ACCOUNT_RETRIEVE, FALSE);
1175 /* Get per-account message amount retrieval limit */
1176 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1177 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1178 if (info->retrieve_limit == 0)
1179 info->retrieve_limit = G_MAXINT;
1181 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1183 /* Set account busy */
1184 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1185 priv->account_name = g_strdup(account_name);
1187 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1192 /* ******************************************************************* */
1193 /* ************************** STORE ACTIONS ************************* */
1194 /* ******************************************************************* */
1198 modest_mail_operation_create_folder (ModestMailOperation *self,
1199 TnyFolderStore *parent,
1202 ModestMailOperationPrivate *priv;
1203 TnyFolder *new_folder = NULL;
1205 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1206 g_return_val_if_fail (name, NULL);
1208 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1211 if (TNY_IS_FOLDER (parent)) {
1212 /* Check folder rules */
1213 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1214 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1215 /* Set status failed and set an error */
1216 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1217 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1218 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1219 _("mail_in_ui_folder_create_error"));
1224 /* Create the folder */
1225 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1226 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1228 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1231 /* Notify about operation end */
1232 modest_mail_operation_notify_end (self);
1238 modest_mail_operation_remove_folder (ModestMailOperation *self,
1240 gboolean remove_to_trash)
1242 TnyAccount *account;
1243 ModestMailOperationPrivate *priv;
1244 ModestTnyFolderRules rules;
1246 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1247 g_return_if_fail (TNY_IS_FOLDER (folder));
1249 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1251 /* Check folder rules */
1252 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1253 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1254 /* Set status failed and set an error */
1255 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1256 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1257 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1258 _("mail_in_ui_folder_delete_error"));
1262 /* Get the account */
1263 account = modest_tny_folder_get_account (folder);
1264 priv->account = g_object_ref(account);
1266 /* Delete folder or move to trash */
1267 if (remove_to_trash) {
1268 TnyFolder *trash_folder = NULL;
1269 trash_folder = modest_tny_account_get_special_folder (account,
1270 TNY_FOLDER_TYPE_TRASH);
1271 /* TODO: error_handling */
1272 modest_mail_operation_xfer_folder (self, folder,
1273 TNY_FOLDER_STORE (trash_folder), TRUE);
1275 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1277 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1278 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1281 g_object_unref (G_OBJECT (parent));
1283 g_object_unref (G_OBJECT (account));
1286 /* Notify about operation end */
1287 modest_mail_operation_notify_end (self);
1291 transfer_folder_status_cb (GObject *obj,
1295 ModestMailOperation *self;
1296 ModestMailOperationPrivate *priv;
1297 ModestMailOperationState *state;
1299 g_return_if_fail (status != NULL);
1300 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1302 self = MODEST_MAIL_OPERATION (user_data);
1303 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1305 if ((status->position == 1) && (status->of_total == 100))
1308 priv->done = status->position;
1309 priv->total = status->of_total;
1311 state = modest_mail_operation_clone_state (self);
1312 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1313 g_slice_free (ModestMailOperationState, state);
1318 transfer_folder_cb (TnyFolder *folder,
1319 TnyFolderStore *into,
1321 TnyFolder *new_folder, GError **err,
1324 ModestMailOperation *self = NULL;
1325 ModestMailOperationPrivate *priv = NULL;
1327 self = MODEST_MAIL_OPERATION (user_data);
1329 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1332 priv->error = g_error_copy (*err);
1334 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1335 } else if (cancelled) {
1336 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1337 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1338 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1339 _("Transference of %s was cancelled."),
1340 tny_folder_get_name (folder));
1343 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1347 g_object_unref (folder);
1348 g_object_unref (into);
1349 if (new_folder != NULL)
1350 g_object_unref (new_folder);
1352 /* Notify about operation end */
1353 modest_mail_operation_notify_end (self);
1357 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1359 TnyFolderStore *parent,
1360 gboolean delete_original)
1362 ModestMailOperationPrivate *priv = NULL;
1363 ModestTnyFolderRules parent_rules, rules;
1365 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1366 g_return_if_fail (TNY_IS_FOLDER (folder));
1367 g_return_if_fail (TNY_IS_FOLDER (parent));
1369 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1371 /* Get account and set it into mail_operation */
1372 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1373 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1375 /* Get folder rules */
1376 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1377 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1379 if (!TNY_IS_FOLDER_STORE (parent)) {
1383 /* The moveable restriction is applied also to copy operation */
1384 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1385 /* Set status failed and set an error */
1386 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1387 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1388 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1389 _("mail_in_ui_folder_move_target_error"));
1391 /* Notify the queue */
1392 modest_mail_operation_notify_end (self);
1393 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1394 /* Set status failed and set an error */
1395 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1396 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1397 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1398 _("FIXME: parent folder does not accept new folders"));
1400 /* Notify the queue */
1401 modest_mail_operation_notify_end (self);
1403 /* Pick references for async calls */
1404 g_object_ref (folder);
1405 g_object_ref (parent);
1407 /* Move/Copy folder */
1408 tny_folder_copy_async (folder,
1410 tny_folder_get_name (folder),
1413 transfer_folder_status_cb,
1419 modest_mail_operation_rename_folder (ModestMailOperation *self,
1423 ModestMailOperationPrivate *priv;
1424 ModestTnyFolderRules rules;
1426 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1427 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1428 g_return_if_fail (name);
1430 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1432 /* Get account and set it into mail_operation */
1433 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1435 /* Check folder rules */
1436 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1437 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1438 /* Set status failed and set an error */
1439 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1440 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1441 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1442 _("FIXME: unable to rename"));
1444 /* Notify about operation end */
1445 modest_mail_operation_notify_end (self);
1447 /* Rename. Camel handles folder subscription/unsubscription */
1448 TnyFolderStore *into;
1450 into = tny_folder_get_folder_store (folder);
1451 tny_folder_copy_async (folder, into, name, TRUE,
1453 transfer_folder_status_cb,
1456 g_object_unref (into);
1461 /* ******************************************************************* */
1462 /* ************************** MSG ACTIONS ************************* */
1463 /* ******************************************************************* */
1465 void modest_mail_operation_get_msg (ModestMailOperation *self,
1467 GetMsgAsyncUserCallback user_callback,
1470 GetMsgAsyncHelper *helper = NULL;
1472 ModestMailOperationPrivate *priv;
1474 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1475 g_return_if_fail (TNY_IS_HEADER (header));
1477 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1478 folder = tny_header_get_folder (header);
1480 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1482 /* Get message from folder */
1484 /* Get account and set it into mail_operation */
1485 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1487 helper = g_slice_new0 (GetMsgAsyncHelper);
1488 helper->mail_op = self;
1489 helper->user_callback = user_callback;
1490 helper->user_data = user_data;
1492 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1494 g_object_unref (G_OBJECT (folder));
1496 /* Set status failed and set an error */
1497 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1498 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1499 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1500 _("Error trying to get a message. No folder found for header"));
1502 /* Notify the queue */
1503 modest_mail_operation_notify_end (self);
1508 get_msg_cb (TnyFolder *folder,
1514 GetMsgAsyncHelper *helper = NULL;
1515 ModestMailOperation *self = NULL;
1516 ModestMailOperationPrivate *priv = NULL;
1518 helper = (GetMsgAsyncHelper *) user_data;
1519 g_return_if_fail (helper != NULL);
1520 self = helper->mail_op;
1521 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1522 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1524 /* Check errors and cancel */
1526 priv->error = g_error_copy (*error);
1527 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1531 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1532 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1533 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1534 _("Error trying to refresh the contents of %s"),
1535 tny_folder_get_name (folder));
1539 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1541 /* If user defined callback function was defined, call it */
1542 if (helper->user_callback) {
1543 helper->user_callback (self, NULL, msg, helper->user_data);
1548 g_slice_free (GetMsgAsyncHelper, helper);
1550 /* Notify about operation end */
1551 modest_mail_operation_notify_end (self);
1555 get_msg_status_cb (GObject *obj,
1559 GetMsgAsyncHelper *helper = NULL;
1560 ModestMailOperation *self;
1561 ModestMailOperationPrivate *priv;
1562 ModestMailOperationState *state;
1564 g_return_if_fail (status != NULL);
1565 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1567 helper = (GetMsgAsyncHelper *) user_data;
1568 g_return_if_fail (helper != NULL);
1570 self = helper->mail_op;
1571 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1573 if ((status->position == 1) && (status->of_total == 100))
1579 state = modest_mail_operation_clone_state (self);
1580 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1581 g_slice_free (ModestMailOperationState, state);
1584 /****************************************************/
1586 ModestMailOperation *mail_op;
1588 GetMsgAsyncUserCallback user_callback;
1590 GDestroyNotify notify;
1594 GetMsgAsyncUserCallback user_callback;
1598 ModestMailOperation *mail_op;
1599 } NotifyGetMsgsInfo;
1603 * Used by get_msgs_full_thread to call the user_callback for each
1604 * message that has been read
1607 notify_get_msgs_full (gpointer data)
1609 NotifyGetMsgsInfo *info;
1611 info = (NotifyGetMsgsInfo *) data;
1613 /* Call the user callback */
1614 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1616 g_slice_free (NotifyGetMsgsInfo, info);
1622 * Used by get_msgs_full_thread to free al the thread resources and to
1623 * call the destroy function for the passed user_data
1626 get_msgs_full_destroyer (gpointer data)
1628 GetFullMsgsInfo *info;
1630 info = (GetFullMsgsInfo *) data;
1633 info->notify (info->user_data);
1636 g_object_unref (info->headers);
1637 g_slice_free (GetFullMsgsInfo, info);
1643 get_msgs_full_thread (gpointer thr_user_data)
1645 GetFullMsgsInfo *info;
1646 ModestMailOperationPrivate *priv = NULL;
1647 TnyIterator *iter = NULL;
1649 info = (GetFullMsgsInfo *) thr_user_data;
1650 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1652 iter = tny_list_create_iterator (info->headers);
1653 while (!tny_iterator_is_done (iter)) {
1657 header = TNY_HEADER (tny_iterator_get_current (iter));
1658 folder = tny_header_get_folder (header);
1660 /* Get message from folder */
1663 /* The callback will call it per each header */
1664 msg = tny_folder_get_msg (folder, header, &(priv->error));
1667 ModestMailOperationState *state;
1672 /* notify progress */
1673 state = modest_mail_operation_clone_state (info->mail_op);
1674 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1675 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1676 pair, (GDestroyNotify) modest_pair_free);
1678 /* The callback is the responsible for
1679 freeing the message */
1680 if (info->user_callback) {
1681 NotifyGetMsgsInfo *info_notify;
1682 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1683 info_notify->user_callback = info->user_callback;
1684 info_notify->mail_op = info->mail_op;
1685 info_notify->header = g_object_ref (header);
1686 info_notify->msg = g_object_ref (msg);
1687 info_notify->user_data = info->user_data;
1688 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1689 notify_get_msgs_full,
1692 g_object_unref (msg);
1695 /* Set status failed and set an error */
1696 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1697 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1698 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1699 "Error trying to get a message. No folder found for header");
1701 g_object_unref (header);
1702 tny_iterator_next (iter);
1705 /* Set operation status */
1706 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1707 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1709 /* Notify about operation end */
1710 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1712 /* Free thread resources. Will be called after all previous idles */
1713 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1719 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1720 TnyList *header_list,
1721 GetMsgAsyncUserCallback user_callback,
1723 GDestroyNotify notify)
1725 TnyHeader *header = NULL;
1726 TnyFolder *folder = NULL;
1728 ModestMailOperationPrivate *priv = NULL;
1729 GetFullMsgsInfo *info = NULL;
1730 gboolean size_ok = TRUE;
1732 TnyIterator *iter = NULL;
1734 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1736 /* Init mail operation */
1737 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1738 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1740 priv->total = tny_list_get_length(header_list);
1742 /* Get account and set it into mail_operation */
1743 if (tny_list_get_length (header_list) >= 1) {
1744 iter = tny_list_create_iterator (header_list);
1745 header = TNY_HEADER (tny_iterator_get_current (iter));
1746 folder = tny_header_get_folder (header);
1747 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1748 g_object_unref (header);
1749 g_object_unref (folder);
1751 if (tny_list_get_length (header_list) == 1) {
1752 g_object_unref (iter);
1757 /* Get msg size limit */
1758 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1759 MODEST_CONF_MSG_SIZE_LIMIT,
1762 g_clear_error (&(priv->error));
1763 max_size = G_MAXINT;
1765 max_size = max_size * KB;
1768 /* Check message size limits. If there is only one message
1769 always retrieve it */
1771 while (!tny_iterator_is_done (iter) && size_ok) {
1772 header = TNY_HEADER (tny_iterator_get_current (iter));
1773 if (tny_header_get_message_size (header) >= max_size)
1775 g_object_unref (header);
1776 tny_iterator_next (iter);
1778 g_object_unref (iter);
1782 /* Create the info */
1783 info = g_slice_new0 (GetFullMsgsInfo);
1784 info->mail_op = self;
1785 info->user_callback = user_callback;
1786 info->user_data = user_data;
1787 info->headers = g_object_ref (header_list);
1788 info->notify = notify;
1790 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1792 /* Set status failed and set an error */
1793 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1794 /* FIXME: the error msg is different for pop */
1795 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1796 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1797 _("emev_ni_ui_imap_msg_size_exceed_error"));
1798 /* Remove from queue and free resources */
1799 modest_mail_operation_notify_end (self);
1807 modest_mail_operation_remove_msg (ModestMailOperation *self,
1809 gboolean remove_to_trash)
1812 ModestMailOperationPrivate *priv;
1814 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1815 g_return_if_fail (TNY_IS_HEADER (header));
1817 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1818 folder = tny_header_get_folder (header);
1820 /* Get account and set it into mail_operation */
1821 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1823 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1825 /* Delete or move to trash */
1826 if (remove_to_trash) {
1827 TnyFolder *trash_folder;
1828 TnyStoreAccount *store_account;
1830 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1831 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1832 TNY_FOLDER_TYPE_TRASH);
1837 headers = tny_simple_list_new ();
1838 tny_list_append (headers, G_OBJECT (header));
1839 g_object_unref (header);
1842 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1843 g_object_unref (headers);
1844 /* g_object_unref (trash_folder); */
1846 ModestMailOperationPrivate *priv;
1848 /* Set status failed and set an error */
1849 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1850 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1851 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1852 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1853 _("Error trying to delete a message. Trash folder not found"));
1856 g_object_unref (G_OBJECT (store_account));
1858 tny_folder_remove_msg (folder, header, &(priv->error));
1860 tny_folder_sync(folder, TRUE, &(priv->error));
1865 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1867 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1870 g_object_unref (G_OBJECT (folder));
1872 /* Notify about operation end */
1873 modest_mail_operation_notify_end (self);
1877 transfer_msgs_status_cb (GObject *obj,
1881 XFerMsgAsyncHelper *helper = NULL;
1882 ModestMailOperation *self;
1883 ModestMailOperationPrivate *priv;
1884 ModestMailOperationState *state;
1887 g_return_if_fail (status != NULL);
1888 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1890 helper = (XFerMsgAsyncHelper *) user_data;
1891 g_return_if_fail (helper != NULL);
1893 self = helper->mail_op;
1894 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1896 if ((status->position == 1) && (status->of_total == 100))
1899 priv->done = status->position;
1900 priv->total = status->of_total;
1902 state = modest_mail_operation_clone_state (self);
1903 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1904 g_slice_free (ModestMailOperationState, state);
1909 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1911 XFerMsgAsyncHelper *helper;
1912 ModestMailOperation *self;
1913 ModestMailOperationPrivate *priv;
1915 helper = (XFerMsgAsyncHelper *) user_data;
1916 self = helper->mail_op;
1918 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1921 priv->error = g_error_copy (*err);
1923 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1924 } else if (cancelled) {
1925 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1926 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1927 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1928 _("Error trying to refresh the contents of %s"),
1929 tny_folder_get_name (folder));
1932 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1935 /* If user defined callback function was defined, call it */
1936 if (helper->user_callback) {
1937 helper->user_callback (priv->source, helper->user_data);
1941 g_object_unref (helper->headers);
1942 g_object_unref (helper->dest_folder);
1943 g_object_unref (helper->mail_op);
1944 g_slice_free (XFerMsgAsyncHelper, helper);
1945 g_object_unref (folder);
1947 /* Notify about operation end */
1948 modest_mail_operation_notify_end (self);
1952 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1955 gboolean delete_original,
1956 XferMsgsAsynUserCallback user_callback,
1959 ModestMailOperationPrivate *priv;
1961 TnyFolder *src_folder;
1962 XFerMsgAsyncHelper *helper;
1964 ModestTnyFolderRules rules;
1966 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1967 g_return_if_fail (TNY_IS_LIST (headers));
1968 g_return_if_fail (TNY_IS_FOLDER (folder));
1970 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1973 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1975 /* Apply folder rules */
1976 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1978 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1979 /* Set status failed and set an error */
1980 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1981 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1982 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1983 _("FIXME: folder does not accept msgs"));
1984 /* Notify the queue */
1985 modest_mail_operation_notify_end (self);
1989 /* Create the helper */
1990 helper = g_slice_new0 (XFerMsgAsyncHelper);
1991 helper->mail_op = g_object_ref(self);
1992 helper->dest_folder = g_object_ref(folder);
1993 helper->headers = g_object_ref(headers);
1994 helper->user_callback = user_callback;
1995 helper->user_data = user_data;
1997 /* Get source folder */
1998 iter = tny_list_create_iterator (headers);
1999 header = TNY_HEADER (tny_iterator_get_current (iter));
2000 src_folder = tny_header_get_folder (header);
2001 g_object_unref (header);
2002 g_object_unref (iter);
2004 /* Get account and set it into mail_operation */
2005 priv->account = modest_tny_folder_get_account (src_folder);
2007 /* Transfer messages */
2008 tny_folder_transfer_msgs_async (src_folder,
2013 transfer_msgs_status_cb,
2019 on_refresh_folder (TnyFolder *folder,
2024 RefreshAsyncHelper *helper = NULL;
2025 ModestMailOperation *self = NULL;
2026 ModestMailOperationPrivate *priv = NULL;
2028 helper = (RefreshAsyncHelper *) user_data;
2029 self = helper->mail_op;
2030 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2033 priv->error = g_error_copy (*error);
2034 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2039 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2040 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2041 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2042 _("Error trying to refresh the contents of %s"),
2043 tny_folder_get_name (folder));
2047 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2050 /* Call user defined callback, if it exists */
2051 if (helper->user_callback)
2052 helper->user_callback (priv->source, folder, helper->user_data);
2055 g_object_unref (helper->mail_op);
2056 g_slice_free (RefreshAsyncHelper, helper);
2057 g_object_unref (folder);
2059 /* Notify about operation end */
2060 modest_mail_operation_notify_end (self);
2064 on_refresh_folder_status_update (GObject *obj,
2068 RefreshAsyncHelper *helper = NULL;
2069 ModestMailOperation *self = NULL;
2070 ModestMailOperationPrivate *priv = NULL;
2071 ModestMailOperationState *state;
2073 g_return_if_fail (user_data != NULL);
2074 g_return_if_fail (status != NULL);
2075 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2077 helper = (RefreshAsyncHelper *) user_data;
2078 self = helper->mail_op;
2079 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2081 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2083 priv->done = status->position;
2084 priv->total = status->of_total;
2086 state = modest_mail_operation_clone_state (self);
2087 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2088 g_slice_free (ModestMailOperationState, state);
2092 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2094 RefreshAsyncUserCallback user_callback,
2097 ModestMailOperationPrivate *priv = NULL;
2098 RefreshAsyncHelper *helper = NULL;
2100 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2102 /* Pick a reference */
2103 g_object_ref (folder);
2105 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2107 /* Get account and set it into mail_operation */
2108 priv->account = modest_tny_folder_get_account (folder);
2110 /* Create the helper */
2111 helper = g_slice_new0 (RefreshAsyncHelper);
2112 helper->mail_op = g_object_ref(self);
2113 helper->user_callback = user_callback;
2114 helper->user_data = user_data;
2116 /* Refresh the folder. TODO: tinymail could issue a status
2117 updates before the callback call then this could happen. We
2118 must review the design */
2119 tny_folder_refresh_async (folder,
2121 on_refresh_folder_status_update,
2127 * It's used by the mail operation queue to notify the observers
2128 * attached to that signal that the operation finished. We need to use
2129 * that because tinymail does not give us the progress of a given
2130 * operation when it finishes (it directly calls the operation
2134 modest_mail_operation_notify_end (ModestMailOperation *self)
2136 ModestMailOperationState *state;
2137 ModestMailOperationPrivate *priv = NULL;
2139 g_return_if_fail (self);
2141 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2144 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
2148 /* Set the account back to not busy */
2149 if (priv->account_name) {
2150 modest_account_mgr_set_account_busy(modest_runtime_get_account_mgr(), priv->account_name,
2152 g_free(priv->account_name);
2153 priv->account_name = NULL;
2156 /* Notify the observers about the mail opertation end */
2157 state = modest_mail_operation_clone_state (self);
2158 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2159 g_slice_free (ModestMailOperationState, state);