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-camel-pop-folder.h>
39 #include <tny-camel-imap-folder.h>
40 #include <tny-camel-mem-stream.h>
41 #include <tny-simple-list.h>
42 #include <tny-send-queue.h>
43 #include <tny-status.h>
44 #include <tny-folder-observer.h>
45 #include <camel/camel-stream-mem.h>
46 #include <glib/gi18n.h>
47 #include "modest-platform.h"
48 #include "modest-account-mgr-helpers.h"
49 #include <modest-tny-account.h>
50 #include <modest-tny-send-queue.h>
51 #include <modest-runtime.h>
52 #include "modest-text-utils.h"
53 #include "modest-tny-msg.h"
54 #include "modest-tny-folder.h"
55 #include "modest-tny-account-store.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-marshal.h"
58 #include "modest-error.h"
59 #include "modest-mail-operation.h"
64 * Remove all these #ifdef stuff when the tinymail's idle calls become
67 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
69 /* 'private'/'protected' functions */
70 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
71 static void modest_mail_operation_init (ModestMailOperation *obj);
72 static void modest_mail_operation_finalize (GObject *obj);
74 static void get_msg_async_cb (TnyFolder *folder,
80 static void get_msg_status_cb (GObject *obj,
84 static void modest_mail_operation_notify_start (ModestMailOperation *self);
85 static void modest_mail_operation_notify_end (ModestMailOperation *self);
87 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
89 gint *last_total_bytes,
90 gint *sum_total_bytes,
92 gboolean increment_done);
94 static guint compute_message_list_size (TnyList *headers);
96 enum _ModestMailOperationSignals
98 PROGRESS_CHANGED_SIGNAL,
99 OPERATION_STARTED_SIGNAL,
100 OPERATION_FINISHED_SIGNAL,
104 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
105 struct _ModestMailOperationPrivate {
111 ErrorCheckingUserCallback error_checking;
112 gpointer error_checking_user_data;
113 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
114 ModestMailOperationStatus status;
115 ModestMailOperationTypeOperation op_type;
118 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
119 MODEST_TYPE_MAIL_OPERATION, \
120 ModestMailOperationPrivate))
122 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
123 priv->status = new_status;\
128 GetMsgAsyncUserCallback user_callback;
131 ModestMailOperation *mail_op;
132 GDestroyNotify destroy_notify;
133 gint last_total_bytes;
134 gint sum_total_bytes;
138 typedef struct _RefreshAsyncHelper {
139 ModestMailOperation *mail_op;
140 RefreshAsyncUserCallback user_callback;
142 } RefreshAsyncHelper;
144 typedef struct _XFerMsgAsyncHelper
146 ModestMailOperation *mail_op;
148 TnyFolder *dest_folder;
149 XferAsyncUserCallback user_callback;
152 gint last_total_bytes;
153 gint sum_total_bytes;
155 } XFerMsgAsyncHelper;
157 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
161 static void modest_mail_operation_create_msg (ModestMailOperation *self,
162 const gchar *from, const gchar *to,
163 const gchar *cc, const gchar *bcc,
164 const gchar *subject, const gchar *plain_body,
165 const gchar *html_body, const GList *attachments_list,
166 const GList *images_list,
167 TnyHeaderFlags priority_flags,
168 ModestMailOperationCreateMsgCallback callback,
171 static gboolean idle_notify_queue (gpointer data);
174 ModestMailOperation *mail_op;
182 GList *attachments_list;
184 TnyHeaderFlags priority_flags;
185 ModestMailOperationCreateMsgCallback callback;
191 ModestMailOperation *mail_op;
193 ModestMailOperationCreateMsgCallback callback;
198 static GObjectClass *parent_class = NULL;
200 static guint signals[NUM_SIGNALS] = {0};
203 modest_mail_operation_get_type (void)
205 static GType my_type = 0;
207 static const GTypeInfo my_info = {
208 sizeof(ModestMailOperationClass),
209 NULL, /* base init */
210 NULL, /* base finalize */
211 (GClassInitFunc) modest_mail_operation_class_init,
212 NULL, /* class finalize */
213 NULL, /* class data */
214 sizeof(ModestMailOperation),
216 (GInstanceInitFunc) modest_mail_operation_init,
219 my_type = g_type_register_static (G_TYPE_OBJECT,
220 "ModestMailOperation",
227 modest_mail_operation_class_init (ModestMailOperationClass *klass)
229 GObjectClass *gobject_class;
230 gobject_class = (GObjectClass*) klass;
232 parent_class = g_type_class_peek_parent (klass);
233 gobject_class->finalize = modest_mail_operation_finalize;
235 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
238 * ModestMailOperation::progress-changed
239 * @self: the #MailOperation that emits the signal
240 * @user_data: user data set when the signal handler was connected
242 * Emitted when the progress of a mail operation changes
244 signals[PROGRESS_CHANGED_SIGNAL] =
245 g_signal_new ("progress-changed",
246 G_TYPE_FROM_CLASS (gobject_class),
248 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
250 g_cclosure_marshal_VOID__POINTER,
251 G_TYPE_NONE, 1, G_TYPE_POINTER);
255 * This signal is issued whenever a mail operation starts, and
256 * starts mean when the tinymail operation is issued. This
257 * means that it could happen that something wrong happens and
258 * the tinymail function is never called. In this situation a
259 * operation-finished will be issued without any
262 signals[OPERATION_STARTED_SIGNAL] =
263 g_signal_new ("operation-started",
264 G_TYPE_FROM_CLASS (gobject_class),
266 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
268 g_cclosure_marshal_VOID__VOID,
273 * This signal is issued whenever a mail operation
274 * finishes. Note that this signal could be issued without any
275 * previous "operation-started" signal, because this last one
276 * is only issued when the tinymail operation is successfully
279 signals[OPERATION_FINISHED_SIGNAL] =
280 g_signal_new ("operation-finished",
281 G_TYPE_FROM_CLASS (gobject_class),
283 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
285 g_cclosure_marshal_VOID__VOID,
290 modest_mail_operation_init (ModestMailOperation *obj)
292 ModestMailOperationPrivate *priv;
294 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
296 priv->account = NULL;
297 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
298 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
303 priv->error_checking = NULL;
304 priv->error_checking_user_data = NULL;
308 modest_mail_operation_finalize (GObject *obj)
310 ModestMailOperationPrivate *priv;
312 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
317 g_error_free (priv->error);
321 g_object_unref (priv->source);
325 g_object_unref (priv->account);
326 priv->account = NULL;
330 G_OBJECT_CLASS(parent_class)->finalize (obj);
334 modest_mail_operation_new (GObject *source)
336 ModestMailOperation *obj;
337 ModestMailOperationPrivate *priv;
339 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
340 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
343 priv->source = g_object_ref(source);
349 modest_mail_operation_new_with_error_handling (GObject *source,
350 ErrorCheckingUserCallback error_handler,
352 ErrorCheckingUserDataDestroyer error_handler_destroyer)
354 ModestMailOperation *obj;
355 ModestMailOperationPrivate *priv;
357 obj = modest_mail_operation_new (source);
358 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
360 g_return_val_if_fail (error_handler != NULL, obj);
361 priv->error_checking = error_handler;
362 priv->error_checking_user_data = user_data;
363 priv->error_checking_user_data_destroyer = error_handler_destroyer;
369 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
371 ModestMailOperationPrivate *priv;
373 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
374 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
376 /* Call the user callback */
377 if (priv->error_checking != NULL)
378 priv->error_checking (self, priv->error_checking_user_data);
382 ModestMailOperationTypeOperation
383 modest_mail_operation_get_type_operation (ModestMailOperation *self)
385 ModestMailOperationPrivate *priv;
387 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
389 return priv->op_type;
393 modest_mail_operation_is_mine (ModestMailOperation *self,
396 ModestMailOperationPrivate *priv;
398 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
399 if (priv->source == NULL) return FALSE;
401 return priv->source == me;
405 modest_mail_operation_get_source (ModestMailOperation *self)
407 ModestMailOperationPrivate *priv;
409 g_return_val_if_fail (self, NULL);
411 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
413 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
417 return (priv->source) ? g_object_ref (priv->source) : NULL;
420 ModestMailOperationStatus
421 modest_mail_operation_get_status (ModestMailOperation *self)
423 ModestMailOperationPrivate *priv;
425 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
426 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
427 MODEST_MAIL_OPERATION_STATUS_INVALID);
429 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
431 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
432 return MODEST_MAIL_OPERATION_STATUS_INVALID;
439 modest_mail_operation_get_error (ModestMailOperation *self)
441 ModestMailOperationPrivate *priv;
443 g_return_val_if_fail (self, NULL);
444 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
446 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
449 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
457 modest_mail_operation_cancel (ModestMailOperation *self)
459 ModestMailOperationPrivate *priv;
460 gboolean canceled = FALSE;
462 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
464 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
466 /* Note that if we call cancel with an already canceled mail
467 operation the progress changed signal won't be emitted */
468 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
472 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
474 /* Cancel the mail operation. We need to wrap it between this
475 start/stop operations to allow following calls to the
477 g_return_val_if_fail (priv->account, FALSE);
479 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
480 ModestTnySendQueue *queue;
481 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account));
482 /* Cancel sending without removing the item */
483 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), FALSE, NULL);
485 /* Cancel operation */
486 tny_account_cancel (priv->account);
493 modest_mail_operation_get_task_done (ModestMailOperation *self)
495 ModestMailOperationPrivate *priv;
497 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
499 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
504 modest_mail_operation_get_task_total (ModestMailOperation *self)
506 ModestMailOperationPrivate *priv;
508 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
510 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
515 modest_mail_operation_is_finished (ModestMailOperation *self)
517 ModestMailOperationPrivate *priv;
518 gboolean retval = FALSE;
520 if (!MODEST_IS_MAIL_OPERATION (self)) {
521 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
525 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
527 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
528 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
529 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
530 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
540 * Creates an image of the current state of a mail operation, the
541 * caller must free it
543 static ModestMailOperationState *
544 modest_mail_operation_clone_state (ModestMailOperation *self)
546 ModestMailOperationState *state;
547 ModestMailOperationPrivate *priv;
549 /* FIXME: this should be fixed properly
551 * in some cases, priv was NULL, so checking here to
554 g_return_val_if_fail (self, NULL);
555 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
556 g_return_val_if_fail (priv, NULL);
561 state = g_slice_new (ModestMailOperationState);
563 state->status = priv->status;
564 state->op_type = priv->op_type;
565 state->done = priv->done;
566 state->total = priv->total;
567 state->finished = modest_mail_operation_is_finished (self);
568 state->bytes_done = 0;
569 state->bytes_total = 0;
574 /* ******************************************************************* */
575 /* ************************** SEND ACTIONS ************************* */
576 /* ******************************************************************* */
579 modest_mail_operation_send_mail (ModestMailOperation *self,
580 TnyTransportAccount *transport_account,
583 TnySendQueue *send_queue = NULL;
584 ModestMailOperationPrivate *priv;
586 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
587 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
588 g_return_if_fail (TNY_IS_MSG (msg));
590 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
592 /* Get account and set it into mail_operation */
593 priv->account = g_object_ref (transport_account);
594 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
598 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
599 if (!TNY_IS_SEND_QUEUE(send_queue)) {
600 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
601 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
602 "modest: could not find send queue for account\n");
603 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
606 /* Add the msg to the queue */
607 modest_mail_operation_notify_start (self);
608 modest_tny_send_queue_add (MODEST_TNY_SEND_QUEUE(send_queue),
612 /* TODO: we're setting always success, do the check in
614 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
617 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)
618 modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
620 /* TODO: do this in the handler of the "msg-sent"
621 signal.Notify about operation end */
622 modest_mail_operation_notify_end (self);
626 idle_create_msg_cb (gpointer idle_data)
628 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
630 /* This is a GDK lock because we are an idle callback and
631 * info->callback can contain Gtk+ code */
633 gdk_threads_enter (); /* CHECKED */
634 info->callback (info->mail_op, info->msg, info->userdata);
636 g_object_unref (info->mail_op);
638 g_object_unref (info->msg);
639 g_slice_free (CreateMsgIdleInfo, info);
640 gdk_threads_leave (); /* CHECKED */
646 create_msg_thread (gpointer thread_data)
648 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
649 TnyMsg *new_msg = NULL;
650 ModestMailOperationPrivate *priv;
652 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
653 if (info->html_body == NULL) {
654 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
655 info->bcc, info->subject, info->plain_body,
656 info->attachments_list);
658 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
659 info->bcc, info->subject, info->html_body,
660 info->plain_body, info->attachments_list,
667 /* Set priority flags in message */
668 header = tny_msg_get_header (new_msg);
669 tny_header_set_flag (header, info->priority_flags);
671 /* Set attachment flags in message */
672 if (info->attachments_list != NULL)
673 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
675 g_object_unref (G_OBJECT(header));
677 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
678 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
679 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
680 "modest: failed to create a new msg\n");
688 g_free (info->plain_body);
689 g_free (info->html_body);
690 g_free (info->subject);
691 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
692 g_list_free (info->attachments_list);
693 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
694 g_list_free (info->images_list);
696 if (info->callback) {
697 CreateMsgIdleInfo *idle_info;
698 idle_info = g_slice_new0 (CreateMsgIdleInfo);
699 idle_info->mail_op = g_object_ref (info->mail_op);
700 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
701 idle_info->callback = info->callback;
702 idle_info->userdata = info->userdata;
703 g_idle_add (idle_create_msg_cb, idle_info);
705 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
708 g_object_unref (info->mail_op);
709 g_slice_free (CreateMsgInfo, info);
714 modest_mail_operation_create_msg (ModestMailOperation *self,
715 const gchar *from, const gchar *to,
716 const gchar *cc, const gchar *bcc,
717 const gchar *subject, const gchar *plain_body,
718 const gchar *html_body,
719 const GList *attachments_list,
720 const GList *images_list,
721 TnyHeaderFlags priority_flags,
722 ModestMailOperationCreateMsgCallback callback,
725 CreateMsgInfo *info = NULL;
727 info = g_slice_new0 (CreateMsgInfo);
728 info->mail_op = g_object_ref (self);
730 info->from = g_strdup (from);
731 info->to = g_strdup (to);
732 info->cc = g_strdup (cc);
733 info->bcc = g_strdup (bcc);
734 info->subject = g_strdup (subject);
735 info->plain_body = g_strdup (plain_body);
736 info->html_body = g_strdup (html_body);
737 info->attachments_list = g_list_copy ((GList *) attachments_list);
738 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
739 info->images_list = g_list_copy ((GList *) images_list);
740 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
741 info->priority_flags = priority_flags;
743 info->callback = callback;
744 info->userdata = userdata;
746 g_thread_create (create_msg_thread, info, FALSE, NULL);
751 TnyTransportAccount *transport_account;
756 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
760 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
761 TnyFolder *draft_folder = NULL;
762 TnyFolder *outbox_folder = NULL;
770 /* Call mail operation */
771 modest_mail_operation_send_mail (self, info->transport_account, msg);
773 /* Remove old mail from its source folder */
774 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
775 TNY_FOLDER_TYPE_DRAFTS);
776 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
777 TNY_FOLDER_TYPE_OUTBOX);
778 if (info->draft_msg != NULL) {
779 TnyFolder *folder = NULL;
780 TnyFolder *src_folder = NULL;
781 TnyFolderType folder_type;
782 folder = tny_msg_get_folder (info->draft_msg);
783 if (folder == NULL) goto end;
784 folder_type = modest_tny_folder_guess_folder_type (folder);
786 if (folder_type == TNY_FOLDER_TYPE_INVALID)
787 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
789 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
790 src_folder = outbox_folder;
792 src_folder = draft_folder;
794 /* Note: This can fail (with a warning) if the message is not really already in a folder,
795 * because this function requires it to have a UID. */
796 header = tny_msg_get_header (info->draft_msg);
797 tny_folder_remove_msg (src_folder, header, NULL);
799 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
800 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
802 g_object_unref (header);
803 g_object_unref (folder);
810 g_object_unref (info->draft_msg);
812 g_object_unref (draft_folder);
814 g_object_unref (outbox_folder);
815 if (info->transport_account)
816 g_object_unref (info->transport_account);
817 g_slice_free (SendNewMailInfo, info);
818 modest_mail_operation_notify_end (self);
822 modest_mail_operation_send_new_mail (ModestMailOperation *self,
823 TnyTransportAccount *transport_account,
825 const gchar *from, const gchar *to,
826 const gchar *cc, const gchar *bcc,
827 const gchar *subject, const gchar *plain_body,
828 const gchar *html_body,
829 const GList *attachments_list,
830 const GList *images_list,
831 TnyHeaderFlags priority_flags)
833 ModestMailOperationPrivate *priv = NULL;
834 SendNewMailInfo *info;
836 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
837 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
839 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
840 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
841 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
843 /* Check parametters */
845 /* Set status failed and set an error */
846 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
847 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
848 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
849 _("Error trying to send a mail. You need to set at least one recipient"));
852 info = g_slice_new0 (SendNewMailInfo);
853 info->transport_account = transport_account;
854 if (transport_account)
855 g_object_ref (transport_account);
856 info->draft_msg = draft_msg;
858 g_object_ref (draft_msg);
861 modest_mail_operation_notify_start (self);
862 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
863 attachments_list, images_list, priority_flags,
864 modest_mail_operation_send_new_mail_cb, info);
870 TnyTransportAccount *transport_account;
872 SaveToDraftstCallback callback;
876 ModestMailOperation *mailop;
877 } SaveToDraftsAddMsgInfo;
880 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
885 ModestMailOperationPrivate *priv = NULL;
886 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
888 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
891 g_warning ("%s: priv->error != NULL", __FUNCTION__);
892 g_error_free(priv->error);
895 priv->error = (err == NULL) ? NULL : g_error_copy(err);
897 if ((!priv->error) && (info->draft_msg != NULL)) {
898 TnyHeader *header = tny_msg_get_header (info->draft_msg);
899 TnyFolder *src_folder = tny_header_get_folder (header);
901 /* Remove the old draft */
902 tny_folder_remove_msg (src_folder, header, NULL);
904 /* Synchronize to expunge and to update the msg counts */
905 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
906 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
908 g_object_unref (G_OBJECT(header));
909 g_object_unref (G_OBJECT(src_folder));
913 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
915 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
917 /* Call the user callback */
919 info->callback (info->mailop, info->msg, info->user_data);
921 if (info->transport_account)
922 g_object_unref (G_OBJECT(info->transport_account));
924 g_object_unref (G_OBJECT (info->draft_msg));
926 g_object_unref (G_OBJECT(info->drafts));
928 g_object_unref (G_OBJECT (info->msg));
929 g_slice_free (SaveToDraftsAddMsgInfo, info);
931 modest_mail_operation_notify_end (info->mailop);
932 g_object_unref(info->mailop);
937 TnyTransportAccount *transport_account;
939 SaveToDraftstCallback callback;
944 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
948 TnyFolder *drafts = NULL;
949 ModestMailOperationPrivate *priv = NULL;
950 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
952 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
955 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
956 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
957 "modest: failed to create a new msg\n");
959 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
960 TNY_FOLDER_TYPE_DRAFTS);
962 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
963 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
964 "modest: failed to create a new msg\n");
969 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
970 cb_info->transport_account = g_object_ref(info->transport_account);
971 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
972 cb_info->callback = info->callback;
973 cb_info->user_data = info->user_data;
974 cb_info->drafts = g_object_ref(drafts);
975 cb_info->msg = g_object_ref(msg);
976 cb_info->mailop = g_object_ref(self);
977 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
980 /* Call the user callback */
981 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
983 info->callback (self, msg, info->user_data);
984 modest_mail_operation_notify_end (self);
988 g_object_unref (G_OBJECT(drafts));
990 g_object_unref (G_OBJECT (info->draft_msg));
991 if (info->transport_account)
992 g_object_unref (G_OBJECT(info->transport_account));
993 g_slice_free (SaveToDraftsInfo, info);
997 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
998 TnyTransportAccount *transport_account,
1000 const gchar *from, const gchar *to,
1001 const gchar *cc, const gchar *bcc,
1002 const gchar *subject, const gchar *plain_body,
1003 const gchar *html_body,
1004 const GList *attachments_list,
1005 const GList *images_list,
1006 TnyHeaderFlags priority_flags,
1007 SaveToDraftstCallback callback,
1010 ModestMailOperationPrivate *priv = NULL;
1011 SaveToDraftsInfo *info = NULL;
1013 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1014 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1016 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1018 /* Get account and set it into mail_operation */
1019 priv->account = g_object_ref (transport_account);
1020 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1022 info = g_slice_new0 (SaveToDraftsInfo);
1023 info->transport_account = g_object_ref (transport_account);
1024 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1025 info->callback = callback;
1026 info->user_data = user_data;
1028 modest_mail_operation_notify_start (self);
1029 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1030 attachments_list, images_list, priority_flags,
1031 modest_mail_operation_save_to_drafts_cb, info);
1036 ModestMailOperation *mail_op;
1037 TnyStoreAccount *account;
1038 TnyTransportAccount *transport_account;
1040 gint retrieve_limit;
1041 gchar *retrieve_type;
1042 gchar *account_name;
1043 UpdateAccountCallback callback;
1045 TnyList *new_headers;
1046 } UpdateAccountInfo;
1050 ModestMailOperation *mail_op;
1051 TnyMimePart *mime_part;
1053 GetMimePartSizeCallback callback;
1055 } GetMimePartSizeInfo;
1057 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1058 /* We use this folder observer to track the headers that have been
1059 * added to a folder */
1062 TnyList *new_headers;
1063 } InternalFolderObserver;
1066 GObjectClass parent;
1067 } InternalFolderObserverClass;
1069 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1071 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1072 internal_folder_observer,
1074 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1078 foreach_add_item (gpointer header, gpointer user_data)
1080 tny_list_prepend (TNY_LIST (user_data),
1081 g_object_ref (G_OBJECT (header)));
1084 /* This is the method that looks for new messages in a folder */
1086 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1088 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1090 TnyFolderChangeChanged changed;
1092 changed = tny_folder_change_get_changed (change);
1094 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1097 /* Get added headers */
1098 list = tny_simple_list_new ();
1099 tny_folder_change_get_added_headers (change, list);
1101 /* Add them to the folder observer */
1102 tny_list_foreach (list, foreach_add_item,
1103 derived->new_headers);
1105 g_object_unref (G_OBJECT (list));
1110 internal_folder_observer_init (InternalFolderObserver *self)
1112 self->new_headers = tny_simple_list_new ();
1115 internal_folder_observer_finalize (GObject *object)
1117 InternalFolderObserver *self;
1119 self = (InternalFolderObserver *) object;
1120 g_object_unref (self->new_headers);
1122 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1125 tny_folder_observer_init (TnyFolderObserverIface *iface)
1127 iface->update_func = internal_folder_observer_update;
1130 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1132 GObjectClass *object_class;
1134 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1135 object_class = (GObjectClass*) klass;
1136 object_class->finalize = internal_folder_observer_finalize;
1142 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
1145 TnyList *folders = tny_simple_list_new ();
1147 tny_folder_store_get_folders (store, folders, query, NULL);
1148 iter = tny_list_create_iterator (folders);
1150 while (!tny_iterator_is_done (iter)) {
1152 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1154 tny_list_prepend (all_folders, G_OBJECT (folder));
1155 recurse_folders (folder, query, all_folders);
1156 g_object_unref (G_OBJECT (folder));
1159 tny_iterator_next (iter);
1161 g_object_unref (G_OBJECT (iter));
1162 g_object_unref (G_OBJECT (folders));
1166 * Issues the "progress-changed" signal. The timer won't be removed,
1167 * so you must call g_source_remove to stop the signal emission
1170 idle_notify_progress (gpointer data)
1172 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1173 ModestMailOperationState *state;
1175 state = modest_mail_operation_clone_state (mail_op);
1177 /* This is a GDK lock because we are an idle callback and
1178 * the handlers of this signal can contain Gtk+ code */
1180 gdk_threads_enter (); /* CHECKED */
1181 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1182 gdk_threads_leave (); /* CHECKED */
1184 g_slice_free (ModestMailOperationState, state);
1190 * Issues the "progress-changed" signal and removes the timer. It uses
1191 * a lock to ensure that the progress information of the mail
1192 * operation is not modified while there are notifications pending
1195 idle_notify_progress_once (gpointer data)
1199 pair = (ModestPair *) data;
1201 /* This is a GDK lock because we are an idle callback and
1202 * the handlers of this signal can contain Gtk+ code */
1204 gdk_threads_enter (); /* CHECKED */
1205 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1206 gdk_threads_leave (); /* CHECKED */
1208 /* Free the state and the reference to the mail operation */
1209 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1210 g_object_unref (pair->first);
1216 * Used to notify the queue from the main
1217 * loop. We call it inside an idle call to achieve that
1220 idle_notify_queue (gpointer data)
1222 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1224 gdk_threads_enter ();
1225 modest_mail_operation_notify_end (mail_op);
1226 gdk_threads_leave ();
1227 g_object_unref (mail_op);
1233 compare_headers_by_date (gconstpointer a,
1236 TnyHeader **header1, **header2;
1237 time_t sent1, sent2;
1239 header1 = (TnyHeader **) a;
1240 header2 = (TnyHeader **) b;
1242 sent1 = tny_header_get_date_sent (*header1);
1243 sent2 = tny_header_get_date_sent (*header2);
1245 /* We want the most recent ones (greater time_t) at the
1254 set_last_updated_idle (gpointer data)
1257 /* This is a GDK lock because we are an idle callback and
1258 * modest_account_mgr_set_last_updated can issue Gtk+ code */
1260 gdk_threads_enter (); /* CHECKED - please recheck */
1262 /* It does not matter if the time is not exactly the same than
1263 the time when this idle was called, it's just an
1264 approximation and it won't be very different */
1266 modest_account_mgr_set_last_updated (modest_runtime_get_account_mgr (),
1270 gdk_threads_leave (); /* CHECKED - please recheck */
1276 idle_update_account_cb (gpointer data)
1278 UpdateAccountInfo *idle_info;
1280 idle_info = (UpdateAccountInfo *) data;
1282 /* This is a GDK lock because we are an idle callback and
1283 * idle_info->callback can contain Gtk+ code */
1285 gdk_threads_enter (); /* CHECKED */
1286 idle_info->callback (idle_info->mail_op,
1287 idle_info->new_headers,
1288 idle_info->user_data);
1289 gdk_threads_leave (); /* CHECKED */
1292 g_object_unref (idle_info->mail_op);
1293 if (idle_info->new_headers)
1294 g_object_unref (idle_info->new_headers);
1301 get_all_folders_from_account (TnyStoreAccount *account,
1304 TnyList *all_folders = NULL;
1305 TnyIterator *iter = NULL;
1306 TnyFolderStoreQuery *query = NULL;
1308 all_folders = tny_simple_list_new ();
1309 query = tny_folder_store_query_new ();
1310 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1311 tny_folder_store_get_folders (TNY_FOLDER_STORE (account),
1318 g_object_unref (all_folders);
1322 iter = tny_list_create_iterator (all_folders);
1323 while (!tny_iterator_is_done (iter)) {
1324 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1326 recurse_folders (folder, query, all_folders);
1327 g_object_unref (folder);
1329 tny_iterator_next (iter);
1331 g_object_unref (G_OBJECT (iter));
1338 update_account_thread (gpointer thr_user_data)
1340 static gboolean first_time = TRUE;
1341 UpdateAccountInfo *info = NULL;
1342 TnyList *all_folders = NULL, *new_headers = NULL;
1343 GPtrArray *new_headers_array = NULL;
1344 TnyIterator *iter = NULL;
1345 ModestMailOperationPrivate *priv = NULL;
1346 ModestTnySendQueue *send_queue = NULL;
1347 gint i = 0, timeout = 0;
1349 info = (UpdateAccountInfo *) thr_user_data;
1350 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1352 /* Get account and set it into mail_operation */
1353 priv->account = g_object_ref (info->account);
1355 /* Get all the folders. We can do it synchronously because
1356 we're already running in a different thread than the UI */
1357 all_folders = get_all_folders_from_account (info->account, &(priv->error));
1359 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1363 /* Update status and notify. We need to call the notification
1364 with a source function in order to call it from the main
1365 loop. We need that in order not to get into trouble with
1366 Gtk+. We use a timeout in order to provide more status
1367 information, because the sync tinymail call does not
1368 provide it for the moment */
1369 timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1371 new_headers_array = g_ptr_array_new ();
1372 iter = tny_list_create_iterator (all_folders);
1374 while (!tny_iterator_is_done (iter) && !priv->error &&
1375 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1377 TnyFolderType folder_type;
1378 TnyFolder *folder = NULL;
1380 folder = TNY_FOLDER (tny_iterator_get_current (iter));
1381 folder_type = tny_folder_get_folder_type (folder);
1383 /* Refresh it only if it's the INBOX */
1384 if (folder_type == TNY_FOLDER_TYPE_INBOX) {
1385 InternalFolderObserver *observer = NULL;
1386 TnyIterator *new_headers_iter = NULL;
1388 /* Refresh the folder. Our observer receives
1389 * the new emails during folder refreshes, so
1390 * we can use observer->new_headers
1392 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1393 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1395 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1397 new_headers_iter = tny_list_create_iterator (observer->new_headers);
1398 while (!tny_iterator_is_done (new_headers_iter)) {
1399 TnyHeader *header = NULL;
1401 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1402 /* Apply per-message size limits */
1403 if (tny_header_get_message_size (header) < info->max_size)
1404 g_ptr_array_add (new_headers_array, g_object_ref (header));
1406 g_object_unref (header);
1407 tny_iterator_next (new_headers_iter);
1409 g_object_unref (new_headers_iter);
1411 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1412 g_object_unref (observer);
1414 /* We no not need to do it the first time,
1415 because it's automatically done by the tree
1417 if (G_LIKELY (!first_time))
1418 tny_folder_poke_status (folder);
1420 g_object_unref (folder);
1422 tny_iterator_next (iter);
1424 g_object_unref (G_OBJECT (iter));
1425 g_source_remove (timeout);
1427 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1428 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1429 new_headers_array->len > 0) {
1433 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1435 /* TODO: Ask the user, instead of just failing,
1436 * showing mail_nc_msg_count_limit_exceeded, with 'Get
1437 * all' and 'Newest only' buttons. */
1438 if (new_headers_array->len > info->retrieve_limit) {
1442 /* Should be get only the headers or the message as well? */
1443 if (g_ascii_strcasecmp (info->retrieve_type,
1444 MODEST_ACCOUNT_RETRIEVE_VALUE_HEADERS_ONLY) != 0) {
1446 priv->total = MIN (new_headers_array->len, info->retrieve_limit);
1447 while (msg_num < priv->total) {
1449 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1450 TnyFolder *folder = tny_header_get_folder (header);
1451 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1452 ModestMailOperationState *state;
1456 /* We can not just use the mail operation because the
1457 values of done and total could change before the
1459 state = modest_mail_operation_clone_state (info->mail_op);
1460 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1461 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1462 pair, (GDestroyNotify) modest_pair_free);
1464 g_object_unref (msg);
1465 g_object_unref (folder);
1472 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1475 /* Copy the headers to a list and free the array */
1476 new_headers = tny_simple_list_new ();
1477 for (i=0; i < new_headers_array->len; i++) {
1478 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1479 tny_list_append (new_headers, G_OBJECT (header));
1481 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1482 g_ptr_array_free (new_headers_array, FALSE);
1485 /* Perform send (if operation was not cancelled) */
1488 if (priv->account != NULL)
1489 g_object_unref (priv->account);
1491 if (info->transport_account) {
1492 priv->account = g_object_ref (info->transport_account);
1494 send_queue = modest_runtime_get_send_queue (info->transport_account);
1496 modest_tny_send_queue_try_to_send (send_queue);
1498 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1499 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1500 "cannot create a send queue for %s\n",
1501 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1502 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1506 /* Check if the operation was a success */
1508 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1510 /* Update the last updated key */
1511 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1512 set_last_updated_idle,
1513 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1514 (GDestroyNotify) g_free);
1518 /* Set the account back to not busy */
1519 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
1520 info->account_name, FALSE);
1522 if (info->callback) {
1523 UpdateAccountInfo *idle_info;
1525 /* This thread is not in the main lock */
1526 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1527 idle_info->mail_op = g_object_ref (info->mail_op);
1528 idle_info->new_headers = (new_headers) ? g_object_ref (new_headers) : NULL;
1529 idle_info->callback = info->callback;
1530 idle_info->user_data = info->user_data;
1531 g_idle_add (idle_update_account_cb, idle_info);
1534 /* Notify about operation end. Note that the info could be
1535 freed before this idle happens, but the mail operation will
1537 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1541 g_object_unref (new_headers);
1543 g_object_unref (all_folders);
1544 g_object_unref (info->account);
1545 if (info->transport_account)
1546 g_object_unref (info->transport_account);
1547 g_free (info->account_name);
1548 g_free (info->retrieve_type);
1549 g_slice_free (UpdateAccountInfo, info);
1557 modest_mail_operation_update_account (ModestMailOperation *self,
1558 const gchar *account_name,
1559 UpdateAccountCallback callback,
1562 GThread *thread = NULL;
1563 UpdateAccountInfo *info = NULL;
1564 ModestMailOperationPrivate *priv = NULL;
1565 ModestAccountMgr *mgr = NULL;
1566 TnyStoreAccount *store_account = NULL;
1567 TnyTransportAccount *transport_account = NULL;
1569 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1570 g_return_val_if_fail (account_name, FALSE);
1572 /* Init mail operation. Set total and done to 0, and do not
1573 update them, this way the progress objects will know that
1574 we have no clue about the number of the objects */
1575 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1578 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1579 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1581 /* Get the store account */
1582 store_account = (TnyStoreAccount *)
1583 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1585 TNY_ACCOUNT_TYPE_STORE);
1587 if (!store_account) {
1588 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1589 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1590 "cannot get tny store account for %s\n", account_name);
1594 priv->account = g_object_ref (store_account);
1596 /* Get the transport account, we can not do it in the thread
1597 due to some problems with dbus */
1598 transport_account = (TnyTransportAccount *)
1599 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1601 if (!transport_account) {
1602 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1603 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1604 "cannot get tny transport account for %s\n", account_name);
1608 /* Create the helper object */
1609 info = g_slice_new (UpdateAccountInfo);
1610 info->mail_op = self;
1611 info->account = store_account;
1612 info->transport_account = transport_account;
1613 info->callback = callback;
1614 info->account_name = g_strdup (account_name);
1615 info->user_data = user_data;
1617 /* Get the message size limit */
1618 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1619 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1620 if (info->max_size == 0)
1621 info->max_size = G_MAXINT;
1623 info->max_size = info->max_size * KB;
1625 /* Get per-account retrieval type */
1626 mgr = modest_runtime_get_account_mgr ();
1627 info->retrieve_type = modest_account_mgr_get_retrieve_type (mgr, account_name);
1629 /* Get per-account message amount retrieval limit */
1630 info->retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, account_name);
1631 if (info->retrieve_limit == 0)
1632 info->retrieve_limit = G_MAXINT;
1634 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1636 /* Set account busy */
1637 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1639 modest_mail_operation_notify_start (self);
1640 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1646 g_object_unref (store_account);
1647 if (transport_account)
1648 g_object_unref (transport_account);
1649 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1651 callback (self, NULL, user_data);
1653 modest_mail_operation_notify_end (self);
1657 /* ******************************************************************* */
1658 /* ************************** STORE ACTIONS ************************* */
1659 /* ******************************************************************* */
1663 modest_mail_operation_create_folder (ModestMailOperation *self,
1664 TnyFolderStore *parent,
1667 ModestMailOperationPrivate *priv;
1668 TnyFolder *new_folder = NULL;
1670 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1671 g_return_val_if_fail (name, NULL);
1673 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1674 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1675 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1676 g_object_ref (parent) :
1677 modest_tny_folder_get_account (TNY_FOLDER (parent));
1679 /* Check for already existing folder */
1680 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1681 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1682 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1683 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1684 _CS("ckdg_ib_folder_already_exists"));
1688 if (TNY_IS_FOLDER (parent)) {
1689 /* Check folder rules */
1690 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1691 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1692 /* Set status failed and set an error */
1693 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1694 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1695 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1696 _("mail_in_ui_folder_create_error"));
1700 if (!strcmp (name, " ") || strchr (name, '/')) {
1701 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1702 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1703 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1704 _("mail_in_ui_folder_create_error"));
1708 /* Create the folder */
1709 modest_mail_operation_notify_start (self);
1710 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1711 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1713 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1716 /* Notify about operation end */
1717 modest_mail_operation_notify_end (self);
1723 modest_mail_operation_remove_folder (ModestMailOperation *self,
1725 gboolean remove_to_trash)
1727 TnyAccount *account;
1728 ModestMailOperationPrivate *priv;
1729 ModestTnyFolderRules rules;
1731 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1732 g_return_if_fail (TNY_IS_FOLDER (folder));
1734 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1736 /* Check folder rules */
1737 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1738 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1739 /* Set status failed and set an error */
1740 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1741 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1742 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1743 _("mail_in_ui_folder_delete_error"));
1747 /* Get the account */
1748 account = modest_tny_folder_get_account (folder);
1749 priv->account = g_object_ref(account);
1750 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1752 /* Delete folder or move to trash */
1753 if (remove_to_trash) {
1754 TnyFolder *trash_folder = NULL;
1755 trash_folder = modest_tny_account_get_special_folder (account,
1756 TNY_FOLDER_TYPE_TRASH);
1757 /* TODO: error_handling */
1759 modest_mail_operation_notify_start (self);
1760 modest_mail_operation_xfer_folder (self, folder,
1761 TNY_FOLDER_STORE (trash_folder),
1763 g_object_unref (trash_folder);
1766 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1768 modest_mail_operation_notify_start (self);
1769 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1770 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1773 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1775 g_object_unref (parent);
1777 g_warning ("%s: could not get parent folder", __FUNCTION__);
1779 g_object_unref (G_OBJECT (account));
1782 /* Notify about operation end */
1783 modest_mail_operation_notify_end (self);
1787 transfer_folder_status_cb (GObject *obj,
1791 ModestMailOperation *self;
1792 ModestMailOperationPrivate *priv;
1793 ModestMailOperationState *state;
1794 XFerMsgAsyncHelper *helper;
1796 g_return_if_fail (status != NULL);
1797 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1799 helper = (XFerMsgAsyncHelper *) user_data;
1800 g_return_if_fail (helper != NULL);
1802 self = helper->mail_op;
1803 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1805 priv->done = status->position;
1806 priv->total = status->of_total;
1808 state = modest_mail_operation_clone_state (self);
1810 /* This is not a GDK lock because we are a Tinymail callback
1811 * which is already GDK locked by Tinymail */
1813 /* no gdk_threads_enter (), CHECKED */
1815 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1817 /* no gdk_threads_leave (), CHECKED */
1819 g_slice_free (ModestMailOperationState, state);
1824 transfer_folder_cb (TnyFolder *folder,
1826 TnyFolderStore *into,
1827 TnyFolder *new_folder,
1831 XFerMsgAsyncHelper *helper;
1832 ModestMailOperation *self = NULL;
1833 ModestMailOperationPrivate *priv = NULL;
1835 helper = (XFerMsgAsyncHelper *) user_data;
1836 g_return_if_fail (helper != NULL);
1838 self = helper->mail_op;
1839 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1842 priv->error = g_error_copy (err);
1844 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1845 } else if (cancelled) {
1846 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1847 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1848 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1849 _("Transference of %s was cancelled."),
1850 tny_folder_get_name (folder));
1853 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1856 /* Notify about operation end */
1857 modest_mail_operation_notify_end (self);
1859 /* If user defined callback function was defined, call it */
1860 if (helper->user_callback) {
1862 /* This is not a GDK lock because we are a Tinymail callback
1863 * which is already GDK locked by Tinymail */
1865 /* no gdk_threads_enter (), CHECKED */
1866 helper->user_callback (self, helper->user_data);
1867 /* no gdk_threads_leave () , CHECKED */
1871 g_object_unref (helper->mail_op);
1872 g_slice_free (XFerMsgAsyncHelper, helper);
1877 * This function checks if the new name is a valid name for our local
1878 * folders account. The new name could not be the same than then name
1879 * of any of the mandatory local folders
1881 * We can not rely on tinymail because tinymail does not check the
1882 * name of the virtual folders that the account could have in the case
1883 * that we're doing a rename (because it directly calls Camel which
1884 * knows nothing about our virtual folders).
1886 * In the case of an actual copy/move (i.e. move/copy a folder between
1887 * accounts) tinymail uses the tny_folder_store_create_account which
1888 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1889 * checks the new name of the folder, so this call in that case
1890 * wouldn't be needed. *But* NOTE that if tinymail changes its
1891 * implementation (if folder transfers within the same account is no
1892 * longer implemented as a rename) this call will allow Modest to work
1895 * If the new name is not valid, this function will set the status to
1896 * failed and will set also an error in the mail operation
1899 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1900 TnyFolderStore *into,
1901 const gchar *new_name)
1903 if (TNY_IS_ACCOUNT (into) &&
1904 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1905 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1907 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1908 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1909 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1910 _CS("ckdg_ib_folder_already_exists"));
1917 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1919 TnyFolderStore *parent,
1920 gboolean delete_original,
1921 XferAsyncUserCallback user_callback,
1924 ModestMailOperationPrivate *priv = NULL;
1925 ModestTnyFolderRules parent_rules = 0, rules;
1926 XFerMsgAsyncHelper *helper = NULL;
1927 const gchar *folder_name = NULL;
1928 const gchar *error_msg;
1930 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1931 g_return_if_fail (TNY_IS_FOLDER (folder));
1932 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1934 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1935 folder_name = tny_folder_get_name (folder);
1937 /* Set the error msg */
1938 error_msg = _("mail_in_ui_folder_move_target_error");
1940 /* Get account and set it into mail_operation */
1941 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1942 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1943 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1945 /* Get folder rules */
1946 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1947 if (TNY_IS_FOLDER (parent))
1948 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1950 /* Apply operation constraints */
1951 if ((gpointer) parent == (gpointer) folder ||
1952 (!TNY_IS_FOLDER_STORE (parent)) ||
1953 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1956 } else if (TNY_IS_FOLDER (parent) &&
1957 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1961 } else if (TNY_IS_FOLDER (parent) &&
1962 TNY_IS_FOLDER_STORE (folder) &&
1963 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1964 TNY_FOLDER_STORE (folder))) {
1965 /* Do not move a parent into a child */
1967 } else if (TNY_IS_FOLDER_STORE (parent) &&
1968 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
1969 /* Check that the new folder name is not used by any
1972 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1973 /* Check that the new folder name is not used by any
1974 special local folder */
1977 /* Create the helper */
1978 helper = g_slice_new0 (XFerMsgAsyncHelper);
1979 helper->mail_op = g_object_ref (self);
1980 helper->dest_folder = NULL;
1981 helper->headers = NULL;
1982 helper->user_callback = user_callback;
1983 helper->user_data = user_data;
1985 /* Move/Copy folder */
1986 modest_mail_operation_notify_start (self);
1987 tny_folder_copy_async (folder,
1989 tny_folder_get_name (folder),
1992 transfer_folder_status_cb,
1998 /* Set status failed and set an error */
1999 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2000 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2001 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2004 /* Call the user callback if exists */
2006 user_callback (self, user_data);
2008 /* Notify the queue */
2009 modest_mail_operation_notify_end (self);
2013 modest_mail_operation_rename_folder (ModestMailOperation *self,
2017 ModestMailOperationPrivate *priv;
2018 ModestTnyFolderRules rules;
2019 XFerMsgAsyncHelper *helper;
2021 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2022 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2023 g_return_if_fail (name);
2025 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2027 /* Get account and set it into mail_operation */
2028 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2029 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2031 /* Check folder rules */
2032 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2033 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2034 /* Set status failed and set an error */
2035 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2036 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2037 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2038 _("FIXME: unable to rename"));
2040 /* Notify about operation end */
2041 modest_mail_operation_notify_end (self);
2042 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2043 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2044 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2045 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2046 _("FIXME: unable to rename"));
2047 /* Notify about operation end */
2048 modest_mail_operation_notify_end (self);
2050 TnyFolderStore *into;
2052 into = tny_folder_get_folder_store (folder);
2054 /* Check that the new folder name is not used by any
2055 special local folder */
2056 if (new_name_valid_if_local_account (priv, into, name)) {
2057 /* Create the helper */
2058 helper = g_slice_new0 (XFerMsgAsyncHelper);
2059 helper->mail_op = g_object_ref(self);
2060 helper->dest_folder = NULL;
2061 helper->headers = NULL;
2062 helper->user_callback = NULL;
2063 helper->user_data = NULL;
2065 /* Rename. Camel handles folder subscription/unsubscription */
2066 modest_mail_operation_notify_start (self);
2067 tny_folder_copy_async (folder, into, name, TRUE,
2069 transfer_folder_status_cb,
2072 modest_mail_operation_notify_end (self);
2074 g_object_unref (into);
2078 /* ******************************************************************* */
2079 /* ************************** MSG ACTIONS ************************* */
2080 /* ******************************************************************* */
2083 modest_mail_operation_get_msg (ModestMailOperation *self,
2085 GetMsgAsyncUserCallback user_callback,
2088 GetMsgInfo *helper = NULL;
2090 ModestMailOperationPrivate *priv;
2092 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2093 g_return_if_fail (TNY_IS_HEADER (header));
2095 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2096 folder = tny_header_get_folder (header);
2098 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2099 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2103 /* Get account and set it into mail_operation */
2104 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2106 /* Check for cached messages */
2107 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2108 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2110 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2112 /* Create the helper */
2113 helper = g_slice_new0 (GetMsgInfo);
2114 helper->header = g_object_ref (header);
2115 helper->mail_op = g_object_ref (self);
2116 helper->user_callback = user_callback;
2117 helper->user_data = user_data;
2118 helper->destroy_notify = NULL;
2119 helper->last_total_bytes = 0;
2120 helper->sum_total_bytes = 0;
2121 helper->total_bytes = tny_header_get_message_size (header);
2123 modest_mail_operation_notify_start (self);
2124 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2126 g_object_unref (G_OBJECT (folder));
2130 get_msg_status_cb (GObject *obj,
2134 GetMsgInfo *helper = NULL;
2136 g_return_if_fail (status != NULL);
2137 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2139 helper = (GetMsgInfo *) user_data;
2140 g_return_if_fail (helper != NULL);
2142 /* Notify progress */
2143 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2144 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2148 get_msg_async_cb (TnyFolder *folder,
2154 GetMsgInfo *info = NULL;
2155 ModestMailOperationPrivate *priv = NULL;
2158 info = (GetMsgInfo *) user_data;
2160 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2162 finished = (priv->done == priv->total) ? TRUE : FALSE;
2165 if (canceled || err) {
2166 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2168 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2169 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2172 /* Set the success status before calling the user callback */
2173 if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2174 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2178 /* Call the user callback */
2179 if (info->user_callback)
2180 info->user_callback (info->mail_op, info->header, canceled,
2181 msg, err, info->user_data);
2183 /* Notify about operation end if this is the last callback */
2185 /* Free user data */
2186 if (info->destroy_notify)
2187 info->destroy_notify (info->user_data);
2189 /* Notify about operation end */
2190 modest_mail_operation_notify_end (info->mail_op);
2194 g_object_unref (info->header);
2195 g_object_unref (info->mail_op);
2196 g_slice_free (GetMsgInfo, info);
2200 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2201 TnyList *header_list,
2202 GetMsgAsyncUserCallback user_callback,
2204 GDestroyNotify notify)
2206 ModestMailOperationPrivate *priv = NULL;
2207 gboolean size_ok = TRUE;
2209 TnyIterator *iter = NULL;
2211 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2213 /* Init mail operation */
2214 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2215 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2216 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2218 priv->total = tny_list_get_length(header_list);
2220 /* Get account and set it into mail_operation */
2221 if (tny_list_get_length (header_list) >= 1) {
2222 iter = tny_list_create_iterator (header_list);
2223 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2225 TnyFolder *folder = tny_header_get_folder (header);
2227 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2228 g_object_unref (folder);
2230 g_object_unref (header);
2233 if (tny_list_get_length (header_list) == 1) {
2234 g_object_unref (iter);
2239 /* Get msg size limit */
2240 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2241 MODEST_CONF_MSG_SIZE_LIMIT,
2244 g_clear_error (&(priv->error));
2245 max_size = G_MAXINT;
2247 max_size = max_size * KB;
2250 /* Check message size limits. If there is only one message
2251 always retrieve it */
2253 while (!tny_iterator_is_done (iter) && size_ok) {
2254 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2256 if (tny_header_get_message_size (header) >= max_size)
2258 g_object_unref (header);
2261 tny_iterator_next (iter);
2263 g_object_unref (iter);
2267 modest_mail_operation_notify_start (self);
2269 iter = tny_list_create_iterator (header_list);
2270 while (!tny_iterator_is_done (iter)) {
2271 GetMsgInfo *msg_info = NULL;
2272 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2273 TnyFolder *folder = tny_header_get_folder (header);
2275 /* Create the message info */
2276 msg_info = g_slice_new0 (GetMsgInfo);
2277 msg_info->mail_op = g_object_ref (self);
2278 msg_info->header = g_object_ref (header);
2279 msg_info->user_callback = user_callback;
2280 msg_info->user_data = user_data;
2281 msg_info->destroy_notify = notify;
2282 msg_info->last_total_bytes = 0;
2283 msg_info->sum_total_bytes = 0;
2284 msg_info->total_bytes = compute_message_list_size (header_list);
2286 /* The callback will call it per each header */
2287 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2289 /* Free and go on */
2290 g_object_unref (header);
2291 g_object_unref (folder);
2292 tny_iterator_next (iter);
2294 g_object_unref (iter);
2296 /* Set status failed and set an error */
2297 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2298 /* FIXME: the error msg is different for pop */
2299 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2300 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2301 _("emev_ni_ui_imap_msg_size_exceed_error"));
2302 /* Remove from queue and free resources */
2303 modest_mail_operation_notify_end (self);
2311 modest_mail_operation_remove_msg (ModestMailOperation *self,
2313 gboolean remove_to_trash /*ignored*/)
2316 ModestMailOperationPrivate *priv;
2318 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2319 g_return_if_fail (TNY_IS_HEADER (header));
2321 if (remove_to_trash)
2322 g_warning ("remove to trash is not implemented");
2324 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2325 folder = tny_header_get_folder (header);
2327 /* Get account and set it into mail_operation */
2328 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2329 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2330 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2332 /* remove message from folder */
2333 tny_folder_remove_msg (folder, header, &(priv->error));
2335 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2336 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2338 modest_mail_operation_notify_start (self);
2340 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2341 TNY_IS_CAMEL_POP_FOLDER (folder))
2342 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> dont expunge */
2344 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2350 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2352 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2355 g_object_unref (G_OBJECT (folder));
2357 /* Notify about operation end */
2358 modest_mail_operation_notify_end (self);
2362 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2364 gboolean remove_to_trash /*ignored*/)
2367 ModestMailOperationPrivate *priv;
2368 TnyIterator *iter = NULL;
2369 TnyHeader *header = NULL;
2370 TnyList *remove_headers = NULL;
2371 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2373 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2374 g_return_if_fail (TNY_IS_LIST (headers));
2376 if (remove_to_trash)
2377 g_warning ("remove to trash is not implemented");
2379 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2381 remove_headers = g_object_ref(headers);
2383 /* Get folder from first header and sync it */
2384 iter = tny_list_create_iterator (headers);
2385 header = TNY_HEADER (tny_iterator_get_current (iter));
2386 folder = tny_header_get_folder (header);
2388 /* Don't remove messages that are being sent */
2389 if (modest_tny_folder_is_local_folder (folder)) {
2390 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2392 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2393 TnyTransportAccount *traccount = NULL;
2394 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2395 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2397 ModestTnySendQueueStatus status;
2398 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2399 TnyIterator *iter = tny_list_create_iterator(headers);
2400 g_object_unref(remove_headers);
2401 remove_headers = TNY_LIST(tny_simple_list_new());
2402 while (!tny_iterator_is_done(iter)) {
2404 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2405 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2406 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2407 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2408 tny_list_append(remove_headers, G_OBJECT(hdr));
2410 g_object_unref(hdr);
2412 tny_iterator_next(iter);
2414 g_object_unref(iter);
2415 g_object_unref(traccount);
2419 /* Get account and set it into mail_operation */
2420 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2421 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2422 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2424 /* remove message from folder */
2425 modest_mail_operation_notify_start (self);
2427 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2429 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2430 TNY_IS_CAMEL_POP_FOLDER (folder))
2431 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> don't expunge */
2434 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2440 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2442 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2445 g_object_unref (remove_headers);
2446 g_object_unref (header);
2447 g_object_unref (iter);
2448 g_object_unref (G_OBJECT (folder));
2450 /* Notify about operation end */
2451 modest_mail_operation_notify_end (self);
2455 notify_progress_of_multiple_messages (ModestMailOperation *self,
2457 gint *last_total_bytes,
2458 gint *sum_total_bytes,
2460 gboolean increment_done)
2462 ModestMailOperationPrivate *priv;
2463 ModestMailOperationState *state;
2464 gboolean is_num_bytes;
2466 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2468 /* We know that tinymail sends us information about
2469 transferred bytes with this particular message */
2470 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2472 state = modest_mail_operation_clone_state (self);
2473 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2474 /* We know that we're in a different message when the
2475 total number of bytes to transfer is different. Of
2476 course it could fail if we're transferring messages
2477 of the same size, but this is a workarround */
2478 if (status->of_total != *last_total_bytes) {
2479 /* We need to increment the done when there is
2480 no information about each individual
2481 message, we need to do this in message
2482 transfers, and we don't do it for getting
2486 *sum_total_bytes += *last_total_bytes;
2487 *last_total_bytes = status->of_total;
2489 state->bytes_done += status->position + *sum_total_bytes;
2490 state->bytes_total = total_bytes;
2492 /* Notify the status change. Only notify about changes
2493 referred to bytes */
2494 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2498 g_slice_free (ModestMailOperationState, state);
2502 transfer_msgs_status_cb (GObject *obj,
2506 XFerMsgAsyncHelper *helper;
2508 g_return_if_fail (status != NULL);
2509 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2511 helper = (XFerMsgAsyncHelper *) user_data;
2512 g_return_if_fail (helper != NULL);
2514 /* Notify progress */
2515 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2516 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2521 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2523 XFerMsgAsyncHelper *helper;
2524 ModestMailOperation *self;
2525 ModestMailOperationPrivate *priv;
2526 TnyIterator *iter = NULL;
2527 TnyHeader *header = NULL;
2529 helper = (XFerMsgAsyncHelper *) user_data;
2530 self = helper->mail_op;
2532 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2535 priv->error = g_error_copy (err);
2537 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2538 } else if (cancelled) {
2539 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2540 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2541 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2542 _("Error trying to refresh the contents of %s"),
2543 tny_folder_get_name (folder));
2546 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2548 /* Update folder counts */
2549 tny_folder_poke_status (folder);
2550 tny_folder_poke_status (helper->dest_folder);
2554 /* Mark headers as deleted and seen */
2555 if ((helper->delete) &&
2556 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2557 iter = tny_list_create_iterator (helper->headers);
2558 while (!tny_iterator_is_done (iter)) {
2559 header = TNY_HEADER (tny_iterator_get_current (iter));
2560 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2561 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2562 g_object_unref (header);
2564 tny_iterator_next (iter);
2570 /* Notify about operation end */
2571 modest_mail_operation_notify_end (self);
2573 /* If user defined callback function was defined, call it */
2574 if (helper->user_callback) {
2575 /* This is not a GDK lock because we are a Tinymail callback and
2576 * Tinymail already acquires the Gdk lock */
2578 /* no gdk_threads_enter (), CHECKED */
2579 helper->user_callback (self, helper->user_data);
2580 /* no gdk_threads_leave (), CHECKED */
2584 if (helper->headers)
2585 g_object_unref (helper->headers);
2586 if (helper->dest_folder)
2587 g_object_unref (helper->dest_folder);
2588 if (helper->mail_op)
2589 g_object_unref (helper->mail_op);
2591 g_object_unref (folder);
2593 g_object_unref (iter);
2594 g_slice_free (XFerMsgAsyncHelper, helper);
2598 compute_message_list_size (TnyList *headers)
2603 iter = tny_list_create_iterator (headers);
2604 while (!tny_iterator_is_done (iter)) {
2605 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2606 size += tny_header_get_message_size (header);
2607 g_object_unref (header);
2608 tny_iterator_next (iter);
2610 g_object_unref (iter);
2616 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2619 gboolean delete_original,
2620 XferAsyncUserCallback user_callback,
2623 ModestMailOperationPrivate *priv = NULL;
2624 TnyIterator *iter = NULL;
2625 TnyFolder *src_folder = NULL;
2626 XFerMsgAsyncHelper *helper = NULL;
2627 TnyHeader *header = NULL;
2628 ModestTnyFolderRules rules = 0;
2630 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2631 g_return_if_fail (headers && TNY_IS_LIST (headers));
2632 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2634 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2635 priv->total = tny_list_get_length (headers);
2637 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2638 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2640 /* Apply folder rules */
2641 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2642 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2643 /* Set status failed and set an error */
2644 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2645 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2646 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2647 _CS("ckct_ib_unable_to_paste_here"));
2648 /* Notify the queue */
2649 modest_mail_operation_notify_end (self);
2653 /* Get source folder */
2654 iter = tny_list_create_iterator (headers);
2655 header = TNY_HEADER (tny_iterator_get_current (iter));
2657 src_folder = tny_header_get_folder (header);
2658 g_object_unref (header);
2660 g_object_unref (iter);
2662 if (src_folder == NULL) {
2663 /* Notify the queue */
2664 modest_mail_operation_notify_end (self);
2666 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2671 /* Check folder source and destination */
2672 if (src_folder == folder) {
2673 /* Set status failed and set an error */
2674 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2675 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2676 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2677 _("mcen_ib_unable_to_copy_samefolder"));
2679 /* Notify the queue */
2680 modest_mail_operation_notify_end (self);
2683 g_object_unref (src_folder);
2687 /* Create the helper */
2688 helper = g_slice_new0 (XFerMsgAsyncHelper);
2689 helper->mail_op = g_object_ref(self);
2690 helper->dest_folder = g_object_ref(folder);
2691 helper->headers = g_object_ref(headers);
2692 helper->user_callback = user_callback;
2693 helper->user_data = user_data;
2694 helper->delete = delete_original;
2695 helper->last_total_bytes = 0;
2696 helper->sum_total_bytes = 0;
2697 helper->total_bytes = compute_message_list_size (headers);
2699 /* Get account and set it into mail_operation */
2700 priv->account = modest_tny_folder_get_account (src_folder);
2702 /* Transfer messages */
2703 modest_mail_operation_notify_start (self);
2704 tny_folder_transfer_msgs_async (src_folder,
2709 transfer_msgs_status_cb,
2715 on_refresh_folder (TnyFolder *folder,
2720 RefreshAsyncHelper *helper = NULL;
2721 ModestMailOperation *self = NULL;
2722 ModestMailOperationPrivate *priv = NULL;
2724 helper = (RefreshAsyncHelper *) user_data;
2725 self = helper->mail_op;
2726 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2728 g_return_if_fail(priv!=NULL);
2731 priv->error = g_error_copy (error);
2732 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2737 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2738 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2739 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2740 _("Error trying to refresh the contents of %s"),
2741 tny_folder_get_name (folder));
2745 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2748 /* Call user defined callback, if it exists */
2749 if (helper->user_callback) {
2751 /* This is not a GDK lock because we are a Tinymail callback and
2752 * Tinymail already acquires the Gdk lock */
2753 helper->user_callback (self, folder, helper->user_data);
2757 g_slice_free (RefreshAsyncHelper, helper);
2759 /* Notify about operation end */
2760 modest_mail_operation_notify_end (self);
2761 g_object_unref(self);
2765 on_refresh_folder_status_update (GObject *obj,
2769 RefreshAsyncHelper *helper = NULL;
2770 ModestMailOperation *self = NULL;
2771 ModestMailOperationPrivate *priv = NULL;
2772 ModestMailOperationState *state;
2774 g_return_if_fail (user_data != NULL);
2775 g_return_if_fail (status != NULL);
2776 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2778 helper = (RefreshAsyncHelper *) user_data;
2779 self = helper->mail_op;
2780 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2782 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2784 priv->done = status->position;
2785 priv->total = status->of_total;
2787 state = modest_mail_operation_clone_state (self);
2789 /* This is not a GDK lock because we are a Tinymail callback and
2790 * Tinymail already acquires the Gdk lock */
2791 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2793 g_slice_free (ModestMailOperationState, state);
2797 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2799 RefreshAsyncUserCallback user_callback,
2802 ModestMailOperationPrivate *priv = NULL;
2803 RefreshAsyncHelper *helper = NULL;
2805 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2807 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2809 /* Get account and set it into mail_operation */
2810 priv->account = modest_tny_folder_get_account (folder);
2811 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2813 /* Create the helper */
2814 helper = g_slice_new0 (RefreshAsyncHelper);
2815 helper->mail_op = g_object_ref(self);
2816 helper->user_callback = user_callback;
2817 helper->user_data = user_data;
2819 /* Refresh the folder. TODO: tinymail could issue a status
2820 updates before the callback call then this could happen. We
2821 must review the design */
2822 modest_mail_operation_notify_start (self);
2823 tny_folder_refresh_async (folder,
2825 on_refresh_folder_status_update,
2831 modest_mail_operation_notify_start (ModestMailOperation *self)
2833 ModestMailOperationPrivate *priv = NULL;
2835 g_return_if_fail (self);
2837 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2839 /* Ensure that all the fields are filled correctly */
2840 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
2842 /* Notify the observers about the mail operation. We do not
2843 wrapp this emission because we assume that this function is
2844 always called from within the main lock */
2845 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
2850 * It's used by the mail operation queue to notify the observers
2851 * attached to that signal that the operation finished. We need to use
2852 * that because tinymail does not give us the progress of a given
2853 * operation when it finishes (it directly calls the operation
2857 modest_mail_operation_notify_end (ModestMailOperation *self)
2859 ModestMailOperationPrivate *priv = NULL;
2861 g_return_if_fail (self);
2863 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2865 /* Notify the observers about the mail operation end. We do
2866 not wrapp this emission because we assume that this
2867 function is always called from within the main lock */
2868 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
2870 /* Remove the error user data */
2871 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
2872 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
2876 modest_mail_operation_get_account (ModestMailOperation *self)
2878 ModestMailOperationPrivate *priv = NULL;
2880 g_return_val_if_fail (self, NULL);
2882 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2884 return (priv->account) ? g_object_ref (priv->account) : NULL;
2888 modest_mail_operation_noop (ModestMailOperation *self)
2890 ModestMailOperationPrivate *priv = NULL;
2892 g_return_if_fail (self);
2894 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2895 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2896 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2900 /* This mail operation does nothing actually */
2901 modest_mail_operation_notify_start (self);
2902 modest_mail_operation_notify_end (self);