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 UpdateAccountInfo *info;
875 TnyList *all_folders = NULL;
876 GPtrArray *new_headers;
877 TnyIterator *iter = NULL;
878 TnyFolderStoreQuery *query = NULL;
879 ModestMailOperationPrivate *priv;
880 ModestTnySendQueue *send_queue;
882 info = (UpdateAccountInfo *) thr_user_data;
883 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
885 /* Get account and set it into mail_operation */
886 priv->account = g_object_ref (info->account);
889 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
890 * show any updates unless we do that
892 if (TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
893 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
895 /* Get all the folders. We can do it synchronously because
896 we're already running in a different thread than the UI */
897 all_folders = tny_simple_list_new ();
898 query = tny_folder_store_query_new ();
899 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
900 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
905 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
909 iter = tny_list_create_iterator (all_folders);
910 while (!tny_iterator_is_done (iter)) {
911 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
913 recurse_folders (folder, query, all_folders);
914 tny_iterator_next (iter);
916 g_object_unref (G_OBJECT (iter));
918 /* Update status and notify. We need to call the notification
919 with a source function in order to call it from the main
920 loop. We need that in order not to get into trouble with
921 Gtk+. We use a timeout in order to provide more status
922 information, because the sync tinymail call does not
923 provide it for the moment */
924 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
926 /* Refresh folders */
927 new_headers = g_ptr_array_new ();
928 iter = tny_list_create_iterator (all_folders);
930 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
932 InternalFolderObserver *observer;
933 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
935 /* Refresh the folder */
936 /* Our observer receives notification of new emails during folder refreshes,
937 * so we can use observer->new_headers.
938 * TODO: This does not seem to be providing accurate numbers.
939 * Possibly the observer is notified asynchronously.
941 observer = g_object_new (internal_folder_observer_get_type (), NULL);
942 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
944 /* This gets the status information (headers) from the server.
945 * We use the blocking version, because we are already in a separate
949 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
950 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
953 /* If the retrieve type is full messages, refresh and get the messages */
954 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
956 iter = tny_list_create_iterator (observer->new_headers);
957 while (!tny_iterator_is_done (iter)) {
958 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
959 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
960 * __FUNCTION__, tny_account_get_id (priv->account),
961 * tny_header_get_subject (header));
964 /* Apply per-message size limits */
965 if (tny_header_get_message_size (header) < info->max_size)
966 g_ptr_array_add (new_headers, g_object_ref (header));
968 g_object_unref (header);
969 tny_iterator_next (iter);
971 g_object_unref (iter);
974 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
975 g_object_unref (observer);
979 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
981 g_object_unref (G_OBJECT (folder));
982 tny_iterator_next (iter);
985 did_a_cancel = FALSE;
987 g_object_unref (G_OBJECT (iter));
988 g_source_remove (timeout);
990 if (new_headers->len > 0) {
994 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
996 /* Apply message count limit */
997 /* If the number of messages exceeds the maximum, ask the
998 * user to download them all,
999 * as per the UI spec "Retrieval Limits" section in 4.4:
1001 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
1002 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
1003 if (new_headers->len > info->retrieve_limit) {
1004 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
1005 * with 'Get all' and 'Newest only' buttons. */
1006 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1007 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1008 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1009 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1010 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1015 priv->total = MIN (new_headers->len, info->retrieve_limit);
1016 while (msg_num < priv->total) {
1018 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1019 TnyFolder *folder = tny_header_get_folder (header);
1020 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1021 ModestMailOperationState *state;
1025 /* We can not just use the mail operation because the
1026 values of done and total could change before the
1028 state = modest_mail_operation_clone_state (info->mail_op);
1029 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1030 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1031 pair, (GDestroyNotify) modest_pair_free);
1033 g_object_unref (msg);
1034 g_object_unref (folder);
1038 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1039 g_ptr_array_free (new_headers, FALSE);
1043 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1046 if (priv->account != NULL)
1047 g_object_unref (priv->account);
1048 priv->account = g_object_ref (info->transport_account);
1050 send_queue = modest_runtime_get_send_queue (info->transport_account);
1052 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
1053 modest_tny_send_queue_try_to_send (send_queue);
1054 g_source_remove (timeout);
1056 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1057 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1058 "cannot create a send queue for %s\n",
1059 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1060 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1063 /* Check if the operation was a success */
1065 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1067 /* Update the last updated key */
1068 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1069 set_last_updated_idle,
1070 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1071 (GDestroyNotify) g_free);
1075 /* Notify about operation end. Note that the info could be
1076 freed before this idle happens, but the mail operation will
1078 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1081 g_object_unref (query);
1082 g_object_unref (all_folders);
1083 g_object_unref (info->account);
1084 g_object_unref (info->transport_account);
1085 g_free (info->retrieve_type);
1086 g_slice_free (UpdateAccountInfo, info);
1092 modest_mail_operation_update_account (ModestMailOperation *self,
1093 const gchar *account_name)
1096 UpdateAccountInfo *info;
1097 ModestMailOperationPrivate *priv;
1098 ModestAccountMgr *mgr;
1099 TnyStoreAccount *modest_account;
1100 TnyTransportAccount *transport_account;
1102 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1103 g_return_val_if_fail (account_name, FALSE);
1105 /* Make sure that we have a connection, and request one
1107 * TODO: Is there some way to trigger this for every attempt to
1108 * use the network? */
1109 if (!modest_platform_connect_and_wait(NULL))
1112 /* Init mail operation. Set total and done to 0, and do not
1113 update them, this way the progress objects will know that
1114 we have no clue about the number of the objects */
1115 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1118 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1120 /* Get the Modest account */
1121 modest_account = (TnyStoreAccount *)
1122 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1124 TNY_ACCOUNT_TYPE_STORE);
1126 if (!modest_account) {
1127 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1128 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1129 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1130 "cannot get tny store account for %s\n", account_name);
1131 modest_mail_operation_notify_end (self);
1137 /* Get the transport account, we can not do it in the thread
1138 due to some problems with dbus */
1139 transport_account = (TnyTransportAccount *)
1140 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1142 if (!transport_account) {
1143 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1144 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1145 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1146 "cannot get tny transport account for %s\n", account_name);
1147 modest_mail_operation_notify_end (self);
1152 /* Create the helper object */
1153 info = g_slice_new (UpdateAccountInfo);
1154 info->mail_op = self;
1155 info->account = modest_account;
1156 info->transport_account = transport_account;
1158 /* Get the message size limit */
1159 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1160 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1161 if (info->max_size == 0)
1162 info->max_size = G_MAXINT;
1164 info->max_size = info->max_size * KB;
1166 /* Get per-account retrieval type */
1167 mgr = modest_runtime_get_account_mgr ();
1168 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1169 MODEST_ACCOUNT_RETRIEVE, FALSE);
1171 /* Get per-account message amount retrieval limit */
1172 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1173 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1174 if (info->retrieve_limit == 0)
1175 info->retrieve_limit = G_MAXINT;
1177 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1179 /* Set account busy */
1180 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1181 priv->account_name = g_strdup(account_name);
1183 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1188 /* ******************************************************************* */
1189 /* ************************** STORE ACTIONS ************************* */
1190 /* ******************************************************************* */
1194 modest_mail_operation_create_folder (ModestMailOperation *self,
1195 TnyFolderStore *parent,
1198 ModestMailOperationPrivate *priv;
1199 TnyFolder *new_folder = NULL;
1201 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1202 g_return_val_if_fail (name, NULL);
1204 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1207 if (TNY_IS_FOLDER (parent)) {
1208 /* Check folder rules */
1209 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1210 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
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_create_error"));
1220 /* Create the folder */
1221 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1222 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1224 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1227 /* Notify about operation end */
1228 modest_mail_operation_notify_end (self);
1234 modest_mail_operation_remove_folder (ModestMailOperation *self,
1236 gboolean remove_to_trash)
1238 TnyAccount *account;
1239 ModestMailOperationPrivate *priv;
1240 ModestTnyFolderRules rules;
1242 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1243 g_return_if_fail (TNY_IS_FOLDER (folder));
1245 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1247 /* Check folder rules */
1248 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1249 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1250 /* Set status failed and set an error */
1251 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1252 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1253 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1254 _("mail_in_ui_folder_delete_error"));
1258 /* Get the account */
1259 account = modest_tny_folder_get_account (folder);
1260 priv->account = g_object_ref(account);
1262 /* Delete folder or move to trash */
1263 if (remove_to_trash) {
1264 TnyFolder *trash_folder = NULL;
1265 trash_folder = modest_tny_account_get_special_folder (account,
1266 TNY_FOLDER_TYPE_TRASH);
1267 /* TODO: error_handling */
1268 modest_mail_operation_xfer_folder (self, folder,
1269 TNY_FOLDER_STORE (trash_folder), TRUE);
1271 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1273 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1274 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1277 g_object_unref (G_OBJECT (parent));
1279 g_object_unref (G_OBJECT (account));
1282 /* Notify about operation end */
1283 modest_mail_operation_notify_end (self);
1287 transfer_folder_status_cb (GObject *obj,
1291 ModestMailOperation *self;
1292 ModestMailOperationPrivate *priv;
1293 ModestMailOperationState *state;
1295 g_return_if_fail (status != NULL);
1296 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1298 self = MODEST_MAIL_OPERATION (user_data);
1299 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1301 if ((status->position == 1) && (status->of_total == 100))
1304 priv->done = status->position;
1305 priv->total = status->of_total;
1307 state = modest_mail_operation_clone_state (self);
1308 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1309 g_slice_free (ModestMailOperationState, state);
1314 transfer_folder_cb (TnyFolder *folder,
1315 TnyFolderStore *into,
1317 TnyFolder *new_folder, GError **err,
1320 ModestMailOperation *self = NULL;
1321 ModestMailOperationPrivate *priv = NULL;
1323 self = MODEST_MAIL_OPERATION (user_data);
1325 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1328 priv->error = g_error_copy (*err);
1330 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1331 } else if (cancelled) {
1332 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1333 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1334 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1335 _("Transference of %s was cancelled."),
1336 tny_folder_get_name (folder));
1339 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1343 g_object_unref (folder);
1344 g_object_unref (into);
1345 if (new_folder != NULL)
1346 g_object_unref (new_folder);
1348 /* Notify about operation end */
1349 modest_mail_operation_notify_end (self);
1353 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1355 TnyFolderStore *parent,
1356 gboolean delete_original)
1358 ModestMailOperationPrivate *priv = NULL;
1359 ModestTnyFolderRules parent_rules, rules;
1361 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1362 g_return_if_fail (TNY_IS_FOLDER (folder));
1363 g_return_if_fail (TNY_IS_FOLDER (parent));
1365 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1367 /* Get account and set it into mail_operation */
1368 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1369 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1371 /* Get folder rules */
1372 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1373 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1375 if (!TNY_IS_FOLDER_STORE (parent)) {
1379 /* The moveable restriction is applied also to copy operation */
1380 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1381 /* Set status failed and set an error */
1382 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1383 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1384 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1385 _("mail_in_ui_folder_move_target_error"));
1387 /* Notify the queue */
1388 modest_mail_operation_notify_end (self);
1389 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1390 /* Set status failed and set an error */
1391 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1392 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1393 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1394 _("FIXME: parent folder does not accept new folders"));
1396 /* Notify the queue */
1397 modest_mail_operation_notify_end (self);
1399 /* Pick references for async calls */
1400 g_object_ref (folder);
1401 g_object_ref (parent);
1403 /* Move/Copy folder */
1404 tny_folder_copy_async (folder,
1406 tny_folder_get_name (folder),
1409 transfer_folder_status_cb,
1415 modest_mail_operation_rename_folder (ModestMailOperation *self,
1419 ModestMailOperationPrivate *priv;
1420 ModestTnyFolderRules rules;
1422 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1423 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1424 g_return_if_fail (name);
1426 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1428 /* Get account and set it into mail_operation */
1429 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1431 /* Check folder rules */
1432 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1433 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1434 /* Set status failed and set an error */
1435 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1436 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1437 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1438 _("FIXME: unable to rename"));
1440 /* Notify about operation end */
1441 modest_mail_operation_notify_end (self);
1443 /* Rename. Camel handles folder subscription/unsubscription */
1444 TnyFolderStore *into;
1446 into = tny_folder_get_folder_store (folder);
1447 tny_folder_copy_async (folder, into, name, TRUE,
1449 transfer_folder_status_cb,
1452 g_object_unref (into);
1457 /* ******************************************************************* */
1458 /* ************************** MSG ACTIONS ************************* */
1459 /* ******************************************************************* */
1461 void modest_mail_operation_get_msg (ModestMailOperation *self,
1463 GetMsgAsyncUserCallback user_callback,
1466 GetMsgAsyncHelper *helper = NULL;
1468 ModestMailOperationPrivate *priv;
1470 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1471 g_return_if_fail (TNY_IS_HEADER (header));
1473 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1474 folder = tny_header_get_folder (header);
1476 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1478 /* Get message from folder */
1480 /* Get account and set it into mail_operation */
1481 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1483 helper = g_slice_new0 (GetMsgAsyncHelper);
1484 helper->mail_op = self;
1485 helper->user_callback = user_callback;
1486 helper->user_data = user_data;
1488 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1490 g_object_unref (G_OBJECT (folder));
1492 /* Set status failed and set an error */
1493 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1494 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1495 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1496 _("Error trying to get a message. No folder found for header"));
1498 /* Notify the queue */
1499 modest_mail_operation_notify_end (self);
1504 get_msg_cb (TnyFolder *folder,
1510 GetMsgAsyncHelper *helper = NULL;
1511 ModestMailOperation *self = NULL;
1512 ModestMailOperationPrivate *priv = NULL;
1514 helper = (GetMsgAsyncHelper *) user_data;
1515 g_return_if_fail (helper != NULL);
1516 self = helper->mail_op;
1517 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1518 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1520 /* Check errors and cancel */
1522 priv->error = g_error_copy (*error);
1523 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1527 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1528 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1529 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1530 _("Error trying to refresh the contents of %s"),
1531 tny_folder_get_name (folder));
1535 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1537 /* If user defined callback function was defined, call it */
1538 if (helper->user_callback) {
1539 helper->user_callback (self, NULL, msg, helper->user_data);
1544 g_slice_free (GetMsgAsyncHelper, helper);
1546 /* Notify about operation end */
1547 modest_mail_operation_notify_end (self);
1551 get_msg_status_cb (GObject *obj,
1555 GetMsgAsyncHelper *helper = NULL;
1556 ModestMailOperation *self;
1557 ModestMailOperationPrivate *priv;
1558 ModestMailOperationState *state;
1560 g_return_if_fail (status != NULL);
1561 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1563 helper = (GetMsgAsyncHelper *) user_data;
1564 g_return_if_fail (helper != NULL);
1566 self = helper->mail_op;
1567 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1569 if ((status->position == 1) && (status->of_total == 100))
1575 state = modest_mail_operation_clone_state (self);
1576 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1577 g_slice_free (ModestMailOperationState, state);
1580 /****************************************************/
1582 ModestMailOperation *mail_op;
1584 GetMsgAsyncUserCallback user_callback;
1586 GDestroyNotify notify;
1590 GetMsgAsyncUserCallback user_callback;
1594 ModestMailOperation *mail_op;
1595 } NotifyGetMsgsInfo;
1599 * Used by get_msgs_full_thread to call the user_callback for each
1600 * message that has been read
1603 notify_get_msgs_full (gpointer data)
1605 NotifyGetMsgsInfo *info;
1607 info = (NotifyGetMsgsInfo *) data;
1609 /* Call the user callback */
1610 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1612 g_slice_free (NotifyGetMsgsInfo, info);
1618 * Used by get_msgs_full_thread to free al the thread resources and to
1619 * call the destroy function for the passed user_data
1622 get_msgs_full_destroyer (gpointer data)
1624 GetFullMsgsInfo *info;
1626 info = (GetFullMsgsInfo *) data;
1629 info->notify (info->user_data);
1632 g_object_unref (info->headers);
1633 g_slice_free (GetFullMsgsInfo, info);
1639 get_msgs_full_thread (gpointer thr_user_data)
1641 GetFullMsgsInfo *info;
1642 ModestMailOperationPrivate *priv = NULL;
1643 TnyIterator *iter = NULL;
1645 info = (GetFullMsgsInfo *) thr_user_data;
1646 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1648 iter = tny_list_create_iterator (info->headers);
1649 while (!tny_iterator_is_done (iter)) {
1653 header = TNY_HEADER (tny_iterator_get_current (iter));
1654 folder = tny_header_get_folder (header);
1656 /* Get message from folder */
1659 /* The callback will call it per each header */
1660 msg = tny_folder_get_msg (folder, header, &(priv->error));
1663 ModestMailOperationState *state;
1668 /* notify progress */
1669 state = modest_mail_operation_clone_state (info->mail_op);
1670 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1671 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1672 pair, (GDestroyNotify) modest_pair_free);
1674 /* The callback is the responsible for
1675 freeing the message */
1676 if (info->user_callback) {
1677 NotifyGetMsgsInfo *info_notify;
1678 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1679 info_notify->user_callback = info->user_callback;
1680 info_notify->mail_op = info->mail_op;
1681 info_notify->header = g_object_ref (header);
1682 info_notify->msg = g_object_ref (msg);
1683 info_notify->user_data = info->user_data;
1684 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1685 notify_get_msgs_full,
1688 g_object_unref (msg);
1691 /* Set status failed and set an error */
1692 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1693 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1694 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1695 "Error trying to get a message. No folder found for header");
1697 g_object_unref (header);
1698 tny_iterator_next (iter);
1701 /* Set operation status */
1702 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1703 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1705 /* Notify about operation end */
1706 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1708 /* Free thread resources. Will be called after all previous idles */
1709 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1715 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1716 TnyList *header_list,
1717 GetMsgAsyncUserCallback user_callback,
1719 GDestroyNotify notify)
1721 TnyHeader *header = NULL;
1722 TnyFolder *folder = NULL;
1724 ModestMailOperationPrivate *priv = NULL;
1725 GetFullMsgsInfo *info = NULL;
1726 gboolean size_ok = TRUE;
1728 TnyIterator *iter = NULL;
1730 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1732 /* Init mail operation */
1733 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1734 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1736 priv->total = tny_list_get_length(header_list);
1738 /* Get account and set it into mail_operation */
1739 if (tny_list_get_length (header_list) >= 1) {
1740 iter = tny_list_create_iterator (header_list);
1741 header = TNY_HEADER (tny_iterator_get_current (iter));
1742 folder = tny_header_get_folder (header);
1743 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1744 g_object_unref (header);
1745 g_object_unref (folder);
1747 if (tny_list_get_length (header_list) == 1) {
1748 g_object_unref (iter);
1753 /* Get msg size limit */
1754 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1755 MODEST_CONF_MSG_SIZE_LIMIT,
1758 g_clear_error (&(priv->error));
1759 max_size = G_MAXINT;
1761 max_size = max_size * KB;
1764 /* Check message size limits. If there is only one message
1765 always retrieve it */
1767 while (!tny_iterator_is_done (iter) && size_ok) {
1768 header = TNY_HEADER (tny_iterator_get_current (iter));
1769 if (tny_header_get_message_size (header) >= max_size)
1771 g_object_unref (header);
1772 tny_iterator_next (iter);
1774 g_object_unref (iter);
1778 /* Create the info */
1779 info = g_slice_new0 (GetFullMsgsInfo);
1780 info->mail_op = self;
1781 info->user_callback = user_callback;
1782 info->user_data = user_data;
1783 info->headers = g_object_ref (header_list);
1784 info->notify = notify;
1786 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1788 /* Set status failed and set an error */
1789 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1790 /* FIXME: the error msg is different for pop */
1791 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1792 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1793 _("emev_ni_ui_imap_msg_size_exceed_error"));
1794 /* Remove from queue and free resources */
1795 modest_mail_operation_notify_end (self);
1803 modest_mail_operation_remove_msg (ModestMailOperation *self,
1805 gboolean remove_to_trash)
1808 ModestMailOperationPrivate *priv;
1810 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1811 g_return_if_fail (TNY_IS_HEADER (header));
1813 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1814 folder = tny_header_get_folder (header);
1816 /* Get account and set it into mail_operation */
1817 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1819 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1821 /* Delete or move to trash */
1822 if (remove_to_trash) {
1823 TnyFolder *trash_folder;
1824 TnyStoreAccount *store_account;
1826 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1827 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1828 TNY_FOLDER_TYPE_TRASH);
1833 headers = tny_simple_list_new ();
1834 tny_list_append (headers, G_OBJECT (header));
1835 g_object_unref (header);
1838 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1839 g_object_unref (headers);
1840 /* g_object_unref (trash_folder); */
1842 ModestMailOperationPrivate *priv;
1844 /* Set status failed and set an error */
1845 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1846 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1847 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1848 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1849 _("Error trying to delete a message. Trash folder not found"));
1852 g_object_unref (G_OBJECT (store_account));
1854 tny_folder_remove_msg (folder, header, &(priv->error));
1856 tny_folder_sync(folder, TRUE, &(priv->error));
1861 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1863 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1866 g_object_unref (G_OBJECT (folder));
1868 /* Notify about operation end */
1869 modest_mail_operation_notify_end (self);
1873 transfer_msgs_status_cb (GObject *obj,
1877 XFerMsgAsyncHelper *helper = NULL;
1878 ModestMailOperation *self;
1879 ModestMailOperationPrivate *priv;
1880 ModestMailOperationState *state;
1883 g_return_if_fail (status != NULL);
1884 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1886 helper = (XFerMsgAsyncHelper *) user_data;
1887 g_return_if_fail (helper != NULL);
1889 self = helper->mail_op;
1890 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1892 if ((status->position == 1) && (status->of_total == 100))
1895 priv->done = status->position;
1896 priv->total = status->of_total;
1898 state = modest_mail_operation_clone_state (self);
1899 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1900 g_slice_free (ModestMailOperationState, state);
1905 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1907 XFerMsgAsyncHelper *helper;
1908 ModestMailOperation *self;
1909 ModestMailOperationPrivate *priv;
1911 helper = (XFerMsgAsyncHelper *) user_data;
1912 self = helper->mail_op;
1914 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1917 priv->error = g_error_copy (*err);
1919 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1920 } else if (cancelled) {
1921 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1922 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1923 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1924 _("Error trying to refresh the contents of %s"),
1925 tny_folder_get_name (folder));
1928 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1931 /* If user defined callback function was defined, call it */
1932 if (helper->user_callback) {
1933 helper->user_callback (priv->source, helper->user_data);
1937 g_object_unref (helper->headers);
1938 g_object_unref (helper->dest_folder);
1939 g_object_unref (helper->mail_op);
1940 g_slice_free (XFerMsgAsyncHelper, helper);
1941 g_object_unref (folder);
1943 /* Notify about operation end */
1944 modest_mail_operation_notify_end (self);
1948 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1951 gboolean delete_original,
1952 XferMsgsAsynUserCallback user_callback,
1955 ModestMailOperationPrivate *priv;
1957 TnyFolder *src_folder;
1958 XFerMsgAsyncHelper *helper;
1960 ModestTnyFolderRules rules;
1962 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1963 g_return_if_fail (TNY_IS_LIST (headers));
1964 g_return_if_fail (TNY_IS_FOLDER (folder));
1966 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1969 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1971 /* Apply folder rules */
1972 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1974 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1975 /* Set status failed and set an error */
1976 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1977 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1978 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1979 _("FIXME: folder does not accept msgs"));
1980 /* Notify the queue */
1981 modest_mail_operation_notify_end (self);
1985 /* Create the helper */
1986 helper = g_slice_new0 (XFerMsgAsyncHelper);
1987 helper->mail_op = g_object_ref(self);
1988 helper->dest_folder = g_object_ref(folder);
1989 helper->headers = g_object_ref(headers);
1990 helper->user_callback = user_callback;
1991 helper->user_data = user_data;
1993 /* Get source folder */
1994 iter = tny_list_create_iterator (headers);
1995 header = TNY_HEADER (tny_iterator_get_current (iter));
1996 src_folder = tny_header_get_folder (header);
1997 g_object_unref (header);
1998 g_object_unref (iter);
2000 /* Get account and set it into mail_operation */
2001 priv->account = modest_tny_folder_get_account (src_folder);
2003 /* Transfer messages */
2004 tny_folder_transfer_msgs_async (src_folder,
2009 transfer_msgs_status_cb,
2015 on_refresh_folder (TnyFolder *folder,
2020 RefreshAsyncHelper *helper = NULL;
2021 ModestMailOperation *self = NULL;
2022 ModestMailOperationPrivate *priv = NULL;
2024 helper = (RefreshAsyncHelper *) user_data;
2025 self = helper->mail_op;
2026 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2029 priv->error = g_error_copy (*error);
2030 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2035 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2036 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2037 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2038 _("Error trying to refresh the contents of %s"),
2039 tny_folder_get_name (folder));
2043 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2046 /* Call user defined callback, if it exists */
2047 if (helper->user_callback)
2048 helper->user_callback (priv->source, folder, helper->user_data);
2051 g_object_unref (helper->mail_op);
2052 g_slice_free (RefreshAsyncHelper, helper);
2053 g_object_unref (folder);
2055 /* Notify about operation end */
2056 modest_mail_operation_notify_end (self);
2060 on_refresh_folder_status_update (GObject *obj,
2064 RefreshAsyncHelper *helper = NULL;
2065 ModestMailOperation *self = NULL;
2066 ModestMailOperationPrivate *priv = NULL;
2067 ModestMailOperationState *state;
2069 g_return_if_fail (user_data != NULL);
2070 g_return_if_fail (status != NULL);
2071 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2073 helper = (RefreshAsyncHelper *) user_data;
2074 self = helper->mail_op;
2075 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2077 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2079 priv->done = status->position;
2080 priv->total = status->of_total;
2082 state = modest_mail_operation_clone_state (self);
2083 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2084 g_slice_free (ModestMailOperationState, state);
2088 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2090 RefreshAsyncUserCallback user_callback,
2093 ModestMailOperationPrivate *priv = NULL;
2094 RefreshAsyncHelper *helper = NULL;
2096 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2098 /* Pick a reference */
2099 g_object_ref (folder);
2101 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2103 /* Get account and set it into mail_operation */
2104 priv->account = modest_tny_folder_get_account (folder);
2106 /* Create the helper */
2107 helper = g_slice_new0 (RefreshAsyncHelper);
2108 helper->mail_op = g_object_ref(self);
2109 helper->user_callback = user_callback;
2110 helper->user_data = user_data;
2112 /* Refresh the folder. TODO: tinymail could issue a status
2113 updates before the callback call then this could happen. We
2114 must review the design */
2115 tny_folder_refresh_async (folder,
2117 on_refresh_folder_status_update,
2123 * It's used by the mail operation queue to notify the observers
2124 * attached to that signal that the operation finished. We need to use
2125 * that because tinymail does not give us the progress of a given
2126 * operation when it finishes (it directly calls the operation
2130 modest_mail_operation_notify_end (ModestMailOperation *self)
2132 ModestMailOperationState *state;
2133 ModestMailOperationPrivate *priv = NULL;
2135 g_return_if_fail (self);
2137 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2140 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
2144 /* Set the account back to not busy */
2145 if (priv->account_name) {
2146 modest_account_mgr_set_account_busy(modest_runtime_get_account_mgr(), priv->account_name,
2148 g_free(priv->account_name);
2149 priv->account_name = NULL;
2152 /* Notify the observers about the mail opertation end */
2153 state = modest_mail_operation_clone_state (self);
2154 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2155 g_slice_free (ModestMailOperationState, state);