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));
960 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
961 * __FUNCTION__, tny_account_get_id (priv->account),
962 * tny_header_get_subject (header));
965 /* Apply per-message size limits */
966 if (tny_header_get_message_size (header) < info->max_size)
967 g_ptr_array_add (new_headers, g_object_ref (header));
969 g_object_unref (header);
970 tny_iterator_next (iter);
972 g_object_unref (iter);
975 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
976 g_object_unref (observer);
980 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
982 g_object_unref (G_OBJECT (folder));
983 tny_iterator_next (iter);
986 did_a_cancel = FALSE;
988 g_object_unref (G_OBJECT (iter));
989 g_source_remove (timeout);
991 if (new_headers->len > 0) {
995 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
997 /* Apply message count limit */
998 /* If the number of messages exceeds the maximum, ask the
999 * user to download them all,
1000 * as per the UI spec "Retrieval Limits" section in 4.4:
1002 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
1003 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
1004 if (new_headers->len > info->retrieve_limit) {
1005 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
1006 * with 'Get all' and 'Newest only' buttons. */
1007 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1008 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1009 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1010 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1011 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1016 priv->total = MIN (new_headers->len, info->retrieve_limit);
1017 while (msg_num < priv->total) {
1019 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1020 TnyFolder *folder = tny_header_get_folder (header);
1021 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1022 ModestMailOperationState *state;
1026 /* We can not just use the mail operation because the
1027 values of done and total could change before the
1029 state = modest_mail_operation_clone_state (info->mail_op);
1030 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1031 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1032 pair, (GDestroyNotify) modest_pair_free);
1034 g_object_unref (msg);
1035 g_object_unref (folder);
1039 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1040 g_ptr_array_free (new_headers, FALSE);
1044 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1047 if (priv->account != NULL)
1048 g_object_unref (priv->account);
1049 priv->account = g_object_ref (info->transport_account);
1051 send_queue = modest_runtime_get_send_queue (info->transport_account);
1053 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
1054 modest_tny_send_queue_try_to_send (send_queue);
1055 g_source_remove (timeout);
1057 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1058 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1059 "cannot create a send queue for %s\n",
1060 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1061 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1064 /* Check if the operation was a success */
1066 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1068 /* Update the last updated key */
1069 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1070 set_last_updated_idle,
1071 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1072 (GDestroyNotify) g_free);
1076 /* Notify about operation end. Note that the info could be
1077 freed before this idle happens, but the mail operation will
1079 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1082 g_object_unref (query);
1083 g_object_unref (all_folders);
1084 g_object_unref (info->account);
1085 g_object_unref (info->transport_account);
1086 g_free (info->retrieve_type);
1087 g_slice_free (UpdateAccountInfo, info);
1095 modest_mail_operation_update_account (ModestMailOperation *self,
1096 const gchar *account_name)
1099 UpdateAccountInfo *info;
1100 ModestMailOperationPrivate *priv;
1101 ModestAccountMgr *mgr;
1102 TnyStoreAccount *modest_account;
1103 TnyTransportAccount *transport_account;
1105 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1106 g_return_val_if_fail (account_name, FALSE);
1108 /* Make sure that we have a connection, and request one
1110 * TODO: Is there some way to trigger this for every attempt to
1111 * use the network? */
1112 if (!modest_platform_connect_and_wait(NULL))
1115 /* Init mail operation. Set total and done to 0, and do not
1116 update them, this way the progress objects will know that
1117 we have no clue about the number of the objects */
1118 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1121 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1123 /* Get the Modest account */
1124 modest_account = (TnyStoreAccount *)
1125 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1127 TNY_ACCOUNT_TYPE_STORE);
1129 if (!modest_account) {
1130 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1131 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1132 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1133 "cannot get tny store account for %s\n", account_name);
1134 modest_mail_operation_notify_end (self);
1140 /* Get the transport account, we can not do it in the thread
1141 due to some problems with dbus */
1142 transport_account = (TnyTransportAccount *)
1143 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1145 if (!transport_account) {
1146 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1147 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1148 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1149 "cannot get tny transport account for %s\n", account_name);
1150 modest_mail_operation_notify_end (self);
1155 /* Create the helper object */
1156 info = g_slice_new (UpdateAccountInfo);
1157 info->mail_op = self;
1158 info->account = modest_account;
1159 info->transport_account = transport_account;
1161 /* Get the message size limit */
1162 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1163 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1164 if (info->max_size == 0)
1165 info->max_size = G_MAXINT;
1167 info->max_size = info->max_size * KB;
1169 /* Get per-account retrieval type */
1170 mgr = modest_runtime_get_account_mgr ();
1171 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1172 MODEST_ACCOUNT_RETRIEVE, FALSE);
1174 /* Get per-account message amount retrieval limit */
1175 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1176 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1177 if (info->retrieve_limit == 0)
1178 info->retrieve_limit = G_MAXINT;
1180 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1182 /* Set account busy */
1183 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1184 priv->account_name = g_strdup(account_name);
1186 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1191 /* ******************************************************************* */
1192 /* ************************** STORE ACTIONS ************************* */
1193 /* ******************************************************************* */
1197 modest_mail_operation_create_folder (ModestMailOperation *self,
1198 TnyFolderStore *parent,
1201 ModestMailOperationPrivate *priv;
1202 TnyFolder *new_folder = NULL;
1204 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1205 g_return_val_if_fail (name, NULL);
1207 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1210 if (TNY_IS_FOLDER (parent)) {
1211 /* Check folder rules */
1212 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1213 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1214 /* Set status failed and set an error */
1215 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1216 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1217 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1218 _("mail_in_ui_folder_create_error"));
1223 /* Create the folder */
1224 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1225 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1227 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1230 /* Notify about operation end */
1231 modest_mail_operation_notify_end (self);
1237 modest_mail_operation_remove_folder (ModestMailOperation *self,
1239 gboolean remove_to_trash)
1241 TnyAccount *account;
1242 ModestMailOperationPrivate *priv;
1243 ModestTnyFolderRules rules;
1245 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1246 g_return_if_fail (TNY_IS_FOLDER (folder));
1248 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1250 /* Check folder rules */
1251 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1252 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1253 /* Set status failed and set an error */
1254 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1255 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1256 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1257 _("mail_in_ui_folder_delete_error"));
1261 /* Get the account */
1262 account = modest_tny_folder_get_account (folder);
1263 priv->account = g_object_ref(account);
1265 /* Delete folder or move to trash */
1266 if (remove_to_trash) {
1267 TnyFolder *trash_folder = NULL;
1268 trash_folder = modest_tny_account_get_special_folder (account,
1269 TNY_FOLDER_TYPE_TRASH);
1270 /* TODO: error_handling */
1271 modest_mail_operation_xfer_folder (self, folder,
1272 TNY_FOLDER_STORE (trash_folder), TRUE);
1274 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1276 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1277 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1280 g_object_unref (G_OBJECT (parent));
1282 g_object_unref (G_OBJECT (account));
1285 /* Notify about operation end */
1286 modest_mail_operation_notify_end (self);
1290 transfer_folder_status_cb (GObject *obj,
1294 ModestMailOperation *self;
1295 ModestMailOperationPrivate *priv;
1296 ModestMailOperationState *state;
1298 g_return_if_fail (status != NULL);
1299 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1301 self = MODEST_MAIL_OPERATION (user_data);
1302 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1304 if ((status->position == 1) && (status->of_total == 100))
1307 priv->done = status->position;
1308 priv->total = status->of_total;
1310 state = modest_mail_operation_clone_state (self);
1311 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1312 g_slice_free (ModestMailOperationState, state);
1317 transfer_folder_cb (TnyFolder *folder,
1318 TnyFolderStore *into,
1320 TnyFolder *new_folder, GError **err,
1323 ModestMailOperation *self = NULL;
1324 ModestMailOperationPrivate *priv = NULL;
1326 self = MODEST_MAIL_OPERATION (user_data);
1328 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1331 priv->error = g_error_copy (*err);
1333 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1334 } else if (cancelled) {
1335 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1336 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1337 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1338 _("Transference of %s was cancelled."),
1339 tny_folder_get_name (folder));
1342 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1346 g_object_unref (folder);
1347 g_object_unref (into);
1348 if (new_folder != NULL)
1349 g_object_unref (new_folder);
1351 /* Notify about operation end */
1352 modest_mail_operation_notify_end (self);
1356 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1358 TnyFolderStore *parent,
1359 gboolean delete_original)
1361 ModestMailOperationPrivate *priv = NULL;
1362 ModestTnyFolderRules parent_rules, rules;
1364 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1365 g_return_if_fail (TNY_IS_FOLDER (folder));
1366 g_return_if_fail (TNY_IS_FOLDER (parent));
1368 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1370 /* Get account and set it into mail_operation */
1371 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1372 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1374 /* Get folder rules */
1375 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1376 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1378 if (!TNY_IS_FOLDER_STORE (parent)) {
1382 /* The moveable restriction is applied also to copy operation */
1383 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1384 /* Set status failed and set an error */
1385 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1386 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1387 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1388 _("mail_in_ui_folder_move_target_error"));
1390 /* Notify the queue */
1391 modest_mail_operation_notify_end (self);
1392 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1393 /* Set status failed and set an error */
1394 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1395 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1396 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1397 _("FIXME: parent folder does not accept new folders"));
1399 /* Notify the queue */
1400 modest_mail_operation_notify_end (self);
1402 /* Pick references for async calls */
1403 g_object_ref (folder);
1404 g_object_ref (parent);
1406 /* Move/Copy folder */
1407 tny_folder_copy_async (folder,
1409 tny_folder_get_name (folder),
1412 transfer_folder_status_cb,
1418 modest_mail_operation_rename_folder (ModestMailOperation *self,
1422 ModestMailOperationPrivate *priv;
1423 ModestTnyFolderRules rules;
1425 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1426 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1427 g_return_if_fail (name);
1429 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1431 /* Get account and set it into mail_operation */
1432 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1434 /* Check folder rules */
1435 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1436 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1437 /* Set status failed and set an error */
1438 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1439 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1440 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1441 _("FIXME: unable to rename"));
1443 /* Notify about operation end */
1444 modest_mail_operation_notify_end (self);
1446 /* Rename. Camel handles folder subscription/unsubscription */
1447 TnyFolderStore *into;
1449 into = tny_folder_get_folder_store (folder);
1450 tny_folder_copy_async (folder, into, name, TRUE,
1452 transfer_folder_status_cb,
1455 g_object_unref (into);
1460 /* ******************************************************************* */
1461 /* ************************** MSG ACTIONS ************************* */
1462 /* ******************************************************************* */
1464 void modest_mail_operation_get_msg (ModestMailOperation *self,
1466 GetMsgAsyncUserCallback user_callback,
1469 GetMsgAsyncHelper *helper = NULL;
1471 ModestMailOperationPrivate *priv;
1473 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1474 g_return_if_fail (TNY_IS_HEADER (header));
1476 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1477 folder = tny_header_get_folder (header);
1479 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1481 /* Get message from folder */
1483 /* Get account and set it into mail_operation */
1484 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1486 helper = g_slice_new0 (GetMsgAsyncHelper);
1487 helper->mail_op = self;
1488 helper->user_callback = user_callback;
1489 helper->user_data = user_data;
1491 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1493 g_object_unref (G_OBJECT (folder));
1495 /* Set status failed and set an error */
1496 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1497 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1498 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1499 _("Error trying to get a message. No folder found for header"));
1501 /* Notify the queue */
1502 modest_mail_operation_notify_end (self);
1507 get_msg_cb (TnyFolder *folder,
1513 GetMsgAsyncHelper *helper = NULL;
1514 ModestMailOperation *self = NULL;
1515 ModestMailOperationPrivate *priv = NULL;
1517 helper = (GetMsgAsyncHelper *) user_data;
1518 g_return_if_fail (helper != NULL);
1519 self = helper->mail_op;
1520 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1521 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1523 /* Check errors and cancel */
1525 priv->error = g_error_copy (*error);
1526 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1530 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1531 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1532 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1533 _("Error trying to refresh the contents of %s"),
1534 tny_folder_get_name (folder));
1538 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1540 /* If user defined callback function was defined, call it */
1541 if (helper->user_callback) {
1542 helper->user_callback (self, NULL, msg, helper->user_data);
1547 g_slice_free (GetMsgAsyncHelper, helper);
1549 /* Notify about operation end */
1550 modest_mail_operation_notify_end (self);
1554 get_msg_status_cb (GObject *obj,
1558 GetMsgAsyncHelper *helper = NULL;
1559 ModestMailOperation *self;
1560 ModestMailOperationPrivate *priv;
1561 ModestMailOperationState *state;
1563 g_return_if_fail (status != NULL);
1564 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1566 helper = (GetMsgAsyncHelper *) user_data;
1567 g_return_if_fail (helper != NULL);
1569 self = helper->mail_op;
1570 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1572 if ((status->position == 1) && (status->of_total == 100))
1578 state = modest_mail_operation_clone_state (self);
1579 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1580 g_slice_free (ModestMailOperationState, state);
1583 /****************************************************/
1585 ModestMailOperation *mail_op;
1587 GetMsgAsyncUserCallback user_callback;
1589 GDestroyNotify notify;
1593 GetMsgAsyncUserCallback user_callback;
1597 ModestMailOperation *mail_op;
1598 } NotifyGetMsgsInfo;
1602 * Used by get_msgs_full_thread to call the user_callback for each
1603 * message that has been read
1606 notify_get_msgs_full (gpointer data)
1608 NotifyGetMsgsInfo *info;
1610 info = (NotifyGetMsgsInfo *) data;
1612 /* Call the user callback */
1613 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1615 g_slice_free (NotifyGetMsgsInfo, info);
1621 * Used by get_msgs_full_thread to free al the thread resources and to
1622 * call the destroy function for the passed user_data
1625 get_msgs_full_destroyer (gpointer data)
1627 GetFullMsgsInfo *info;
1629 info = (GetFullMsgsInfo *) data;
1632 info->notify (info->user_data);
1635 g_object_unref (info->headers);
1636 g_slice_free (GetFullMsgsInfo, info);
1642 get_msgs_full_thread (gpointer thr_user_data)
1644 GetFullMsgsInfo *info;
1645 ModestMailOperationPrivate *priv = NULL;
1646 TnyIterator *iter = NULL;
1648 info = (GetFullMsgsInfo *) thr_user_data;
1649 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1651 iter = tny_list_create_iterator (info->headers);
1652 while (!tny_iterator_is_done (iter)) {
1656 header = TNY_HEADER (tny_iterator_get_current (iter));
1657 folder = tny_header_get_folder (header);
1659 /* Get message from folder */
1662 /* The callback will call it per each header */
1663 msg = tny_folder_get_msg (folder, header, &(priv->error));
1666 ModestMailOperationState *state;
1671 /* notify progress */
1672 state = modest_mail_operation_clone_state (info->mail_op);
1673 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1674 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1675 pair, (GDestroyNotify) modest_pair_free);
1677 /* The callback is the responsible for
1678 freeing the message */
1679 if (info->user_callback) {
1680 NotifyGetMsgsInfo *info_notify;
1681 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1682 info_notify->user_callback = info->user_callback;
1683 info_notify->mail_op = info->mail_op;
1684 info_notify->header = g_object_ref (header);
1685 info_notify->msg = g_object_ref (msg);
1686 info_notify->user_data = info->user_data;
1687 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1688 notify_get_msgs_full,
1691 g_object_unref (msg);
1694 /* Set status failed and set an error */
1695 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1696 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1697 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1698 "Error trying to get a message. No folder found for header");
1700 g_object_unref (header);
1701 tny_iterator_next (iter);
1704 /* Set operation status */
1705 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1706 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1708 /* Notify about operation end */
1709 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
1711 /* Free thread resources. Will be called after all previous idles */
1712 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1718 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1719 TnyList *header_list,
1720 GetMsgAsyncUserCallback user_callback,
1722 GDestroyNotify notify)
1724 TnyHeader *header = NULL;
1725 TnyFolder *folder = NULL;
1727 ModestMailOperationPrivate *priv = NULL;
1728 GetFullMsgsInfo *info = NULL;
1729 gboolean size_ok = TRUE;
1731 TnyIterator *iter = NULL;
1733 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1735 /* Init mail operation */
1736 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1737 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1739 priv->total = tny_list_get_length(header_list);
1741 /* Get account and set it into mail_operation */
1742 if (tny_list_get_length (header_list) >= 1) {
1743 iter = tny_list_create_iterator (header_list);
1744 header = TNY_HEADER (tny_iterator_get_current (iter));
1745 folder = tny_header_get_folder (header);
1746 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1747 g_object_unref (header);
1748 g_object_unref (folder);
1750 if (tny_list_get_length (header_list) == 1) {
1751 g_object_unref (iter);
1756 /* Get msg size limit */
1757 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1758 MODEST_CONF_MSG_SIZE_LIMIT,
1761 g_clear_error (&(priv->error));
1762 max_size = G_MAXINT;
1764 max_size = max_size * KB;
1767 /* Check message size limits. If there is only one message
1768 always retrieve it */
1770 while (!tny_iterator_is_done (iter) && size_ok) {
1771 header = TNY_HEADER (tny_iterator_get_current (iter));
1772 if (tny_header_get_message_size (header) >= max_size)
1774 g_object_unref (header);
1775 tny_iterator_next (iter);
1777 g_object_unref (iter);
1781 /* Create the info */
1782 info = g_slice_new0 (GetFullMsgsInfo);
1783 info->mail_op = self;
1784 info->user_callback = user_callback;
1785 info->user_data = user_data;
1786 info->headers = g_object_ref (header_list);
1787 info->notify = notify;
1789 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1791 /* Set status failed and set an error */
1792 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1793 /* FIXME: the error msg is different for pop */
1794 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1795 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1796 _("emev_ni_ui_imap_msg_size_exceed_error"));
1797 /* Remove from queue and free resources */
1798 modest_mail_operation_notify_end (self);
1806 modest_mail_operation_remove_msg (ModestMailOperation *self,
1808 gboolean remove_to_trash)
1811 ModestMailOperationPrivate *priv;
1813 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1814 g_return_if_fail (TNY_IS_HEADER (header));
1816 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1817 folder = tny_header_get_folder (header);
1819 /* Get account and set it into mail_operation */
1820 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1822 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1824 /* Delete or move to trash */
1825 if (remove_to_trash) {
1826 TnyFolder *trash_folder;
1827 TnyStoreAccount *store_account;
1829 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1830 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1831 TNY_FOLDER_TYPE_TRASH);
1836 headers = tny_simple_list_new ();
1837 tny_list_append (headers, G_OBJECT (header));
1838 g_object_unref (header);
1841 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1842 g_object_unref (headers);
1843 /* g_object_unref (trash_folder); */
1845 ModestMailOperationPrivate *priv;
1847 /* Set status failed and set an error */
1848 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1849 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1850 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1851 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1852 _("Error trying to delete a message. Trash folder not found"));
1855 g_object_unref (G_OBJECT (store_account));
1857 tny_folder_remove_msg (folder, header, &(priv->error));
1859 tny_folder_sync(folder, TRUE, &(priv->error));
1864 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1866 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1869 g_object_unref (G_OBJECT (folder));
1871 /* Notify about operation end */
1872 modest_mail_operation_notify_end (self);
1876 transfer_msgs_status_cb (GObject *obj,
1880 XFerMsgAsyncHelper *helper = NULL;
1881 ModestMailOperation *self;
1882 ModestMailOperationPrivate *priv;
1883 ModestMailOperationState *state;
1886 g_return_if_fail (status != NULL);
1887 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1889 helper = (XFerMsgAsyncHelper *) user_data;
1890 g_return_if_fail (helper != NULL);
1892 self = helper->mail_op;
1893 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1895 if ((status->position == 1) && (status->of_total == 100))
1898 priv->done = status->position;
1899 priv->total = status->of_total;
1901 state = modest_mail_operation_clone_state (self);
1902 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1903 g_slice_free (ModestMailOperationState, state);
1908 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1910 XFerMsgAsyncHelper *helper;
1911 ModestMailOperation *self;
1912 ModestMailOperationPrivate *priv;
1914 helper = (XFerMsgAsyncHelper *) user_data;
1915 self = helper->mail_op;
1917 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1920 priv->error = g_error_copy (*err);
1922 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1923 } else if (cancelled) {
1924 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1925 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1926 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1927 _("Error trying to refresh the contents of %s"),
1928 tny_folder_get_name (folder));
1931 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1934 /* If user defined callback function was defined, call it */
1935 if (helper->user_callback) {
1936 helper->user_callback (priv->source, helper->user_data);
1940 g_object_unref (helper->headers);
1941 g_object_unref (helper->dest_folder);
1942 g_object_unref (helper->mail_op);
1943 g_slice_free (XFerMsgAsyncHelper, helper);
1944 g_object_unref (folder);
1946 /* Notify about operation end */
1947 modest_mail_operation_notify_end (self);
1951 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1954 gboolean delete_original,
1955 XferMsgsAsynUserCallback user_callback,
1958 ModestMailOperationPrivate *priv;
1960 TnyFolder *src_folder;
1961 XFerMsgAsyncHelper *helper;
1963 ModestTnyFolderRules rules;
1965 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1966 g_return_if_fail (TNY_IS_LIST (headers));
1967 g_return_if_fail (TNY_IS_FOLDER (folder));
1969 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1972 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1974 /* Apply folder rules */
1975 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1977 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1978 /* Set status failed and set an error */
1979 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1980 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1981 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1982 _("FIXME: folder does not accept msgs"));
1983 /* Notify the queue */
1984 modest_mail_operation_notify_end (self);
1988 /* Create the helper */
1989 helper = g_slice_new0 (XFerMsgAsyncHelper);
1990 helper->mail_op = g_object_ref(self);
1991 helper->dest_folder = g_object_ref(folder);
1992 helper->headers = g_object_ref(headers);
1993 helper->user_callback = user_callback;
1994 helper->user_data = user_data;
1996 /* Get source folder */
1997 iter = tny_list_create_iterator (headers);
1998 header = TNY_HEADER (tny_iterator_get_current (iter));
1999 src_folder = tny_header_get_folder (header);
2000 g_object_unref (header);
2001 g_object_unref (iter);
2003 /* Get account and set it into mail_operation */
2004 priv->account = modest_tny_folder_get_account (src_folder);
2006 /* Transfer messages */
2007 tny_folder_transfer_msgs_async (src_folder,
2012 transfer_msgs_status_cb,
2018 on_refresh_folder (TnyFolder *folder,
2023 RefreshAsyncHelper *helper = NULL;
2024 ModestMailOperation *self = NULL;
2025 ModestMailOperationPrivate *priv = NULL;
2027 helper = (RefreshAsyncHelper *) user_data;
2028 self = helper->mail_op;
2029 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2032 priv->error = g_error_copy (*error);
2033 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2038 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2039 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2040 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2041 _("Error trying to refresh the contents of %s"),
2042 tny_folder_get_name (folder));
2046 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2049 /* Call user defined callback, if it exists */
2050 if (helper->user_callback)
2051 helper->user_callback (priv->source, folder, helper->user_data);
2054 g_object_unref (helper->mail_op);
2055 g_slice_free (RefreshAsyncHelper, helper);
2056 g_object_unref (folder);
2058 /* Notify about operation end */
2059 modest_mail_operation_notify_end (self);
2063 on_refresh_folder_status_update (GObject *obj,
2067 RefreshAsyncHelper *helper = NULL;
2068 ModestMailOperation *self = NULL;
2069 ModestMailOperationPrivate *priv = NULL;
2070 ModestMailOperationState *state;
2072 g_return_if_fail (user_data != NULL);
2073 g_return_if_fail (status != NULL);
2074 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2076 helper = (RefreshAsyncHelper *) user_data;
2077 self = helper->mail_op;
2078 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2080 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2082 priv->done = status->position;
2083 priv->total = status->of_total;
2085 state = modest_mail_operation_clone_state (self);
2086 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2087 g_slice_free (ModestMailOperationState, state);
2091 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2093 RefreshAsyncUserCallback user_callback,
2096 ModestMailOperationPrivate *priv = NULL;
2097 RefreshAsyncHelper *helper = NULL;
2099 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2101 /* Pick a reference */
2102 g_object_ref (folder);
2104 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2106 /* Get account and set it into mail_operation */
2107 priv->account = modest_tny_folder_get_account (folder);
2109 /* Create the helper */
2110 helper = g_slice_new0 (RefreshAsyncHelper);
2111 helper->mail_op = g_object_ref(self);
2112 helper->user_callback = user_callback;
2113 helper->user_data = user_data;
2115 /* Refresh the folder. TODO: tinymail could issue a status
2116 updates before the callback call then this could happen. We
2117 must review the design */
2118 tny_folder_refresh_async (folder,
2120 on_refresh_folder_status_update,
2126 * It's used by the mail operation queue to notify the observers
2127 * attached to that signal that the operation finished. We need to use
2128 * that because tinymail does not give us the progress of a given
2129 * operation when it finishes (it directly calls the operation
2133 modest_mail_operation_notify_end (ModestMailOperation *self)
2135 ModestMailOperationState *state;
2136 ModestMailOperationPrivate *priv = NULL;
2138 g_return_if_fail (self);
2140 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2143 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
2147 /* Set the account back to not busy */
2148 if (priv->account_name) {
2149 modest_account_mgr_set_account_busy(modest_runtime_get_account_mgr(), priv->account_name,
2151 g_free(priv->account_name);
2152 priv->account_name = NULL;
2155 /* Notify the observers about the mail opertation end */
2156 state = modest_mail_operation_clone_state (self);
2157 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2158 g_slice_free (ModestMailOperationState, state);