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;
1776 g_object_unref (G_OBJECT (parent));
1778 g_object_unref (G_OBJECT (account));
1781 /* Notify about operation end */
1782 modest_mail_operation_notify_end (self);
1786 transfer_folder_status_cb (GObject *obj,
1790 ModestMailOperation *self;
1791 ModestMailOperationPrivate *priv;
1792 ModestMailOperationState *state;
1793 XFerMsgAsyncHelper *helper;
1795 g_return_if_fail (status != NULL);
1796 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1798 helper = (XFerMsgAsyncHelper *) user_data;
1799 g_return_if_fail (helper != NULL);
1801 self = helper->mail_op;
1802 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1804 priv->done = status->position;
1805 priv->total = status->of_total;
1807 state = modest_mail_operation_clone_state (self);
1809 /* This is not a GDK lock because we are a Tinymail callback
1810 * which is already GDK locked by Tinymail */
1812 /* no gdk_threads_enter (), CHECKED */
1814 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1816 /* no gdk_threads_leave (), CHECKED */
1818 g_slice_free (ModestMailOperationState, state);
1823 transfer_folder_cb (TnyFolder *folder,
1825 TnyFolderStore *into,
1826 TnyFolder *new_folder,
1830 XFerMsgAsyncHelper *helper;
1831 ModestMailOperation *self = NULL;
1832 ModestMailOperationPrivate *priv = NULL;
1834 helper = (XFerMsgAsyncHelper *) user_data;
1835 g_return_if_fail (helper != NULL);
1837 self = helper->mail_op;
1838 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1841 priv->error = g_error_copy (err);
1843 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1844 } else if (cancelled) {
1845 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1846 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1847 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1848 _("Transference of %s was cancelled."),
1849 tny_folder_get_name (folder));
1852 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1855 /* Notify about operation end */
1856 modest_mail_operation_notify_end (self);
1858 /* If user defined callback function was defined, call it */
1859 if (helper->user_callback) {
1861 /* This is not a GDK lock because we are a Tinymail callback
1862 * which is already GDK locked by Tinymail */
1864 /* no gdk_threads_enter (), CHECKED */
1865 helper->user_callback (self, helper->user_data);
1866 /* no gdk_threads_leave () , CHECKED */
1870 g_object_unref (helper->mail_op);
1871 g_slice_free (XFerMsgAsyncHelper, helper);
1876 * This function checks if the new name is a valid name for our local
1877 * folders account. The new name could not be the same than then name
1878 * of any of the mandatory local folders
1880 * We can not rely on tinymail because tinymail does not check the
1881 * name of the virtual folders that the account could have in the case
1882 * that we're doing a rename (because it directly calls Camel which
1883 * knows nothing about our virtual folders).
1885 * In the case of an actual copy/move (i.e. move/copy a folder between
1886 * accounts) tinymail uses the tny_folder_store_create_account which
1887 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1888 * checks the new name of the folder, so this call in that case
1889 * wouldn't be needed. *But* NOTE that if tinymail changes its
1890 * implementation (if folder transfers within the same account is no
1891 * longer implemented as a rename) this call will allow Modest to work
1894 * If the new name is not valid, this function will set the status to
1895 * failed and will set also an error in the mail operation
1898 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1899 TnyFolderStore *into,
1900 const gchar *new_name)
1902 if (TNY_IS_ACCOUNT (into) &&
1903 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1904 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1906 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1907 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1908 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1909 _CS("ckdg_ib_folder_already_exists"));
1916 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1918 TnyFolderStore *parent,
1919 gboolean delete_original,
1920 XferAsyncUserCallback user_callback,
1923 ModestMailOperationPrivate *priv = NULL;
1924 ModestTnyFolderRules parent_rules = 0, rules;
1925 XFerMsgAsyncHelper *helper = NULL;
1926 const gchar *folder_name = NULL;
1927 const gchar *error_msg;
1929 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1930 g_return_if_fail (TNY_IS_FOLDER (folder));
1931 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1933 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1934 folder_name = tny_folder_get_name (folder);
1936 /* Set the error msg */
1937 error_msg = _("mail_in_ui_folder_move_target_error");
1939 /* Get account and set it into mail_operation */
1940 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1941 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1942 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1944 /* Get folder rules */
1945 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1946 if (TNY_IS_FOLDER (parent))
1947 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1949 /* Apply operation constraints */
1950 if ((gpointer) parent == (gpointer) folder ||
1951 (!TNY_IS_FOLDER_STORE (parent)) ||
1952 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1955 } else if (TNY_IS_FOLDER (parent) &&
1956 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1960 } else if (TNY_IS_FOLDER (parent) &&
1961 TNY_IS_FOLDER_STORE (folder) &&
1962 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1963 TNY_FOLDER_STORE (folder))) {
1964 /* Do not move a parent into a child */
1966 } else if (TNY_IS_FOLDER_STORE (parent) &&
1967 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
1968 /* Check that the new folder name is not used by any
1971 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1972 /* Check that the new folder name is not used by any
1973 special local folder */
1976 /* Create the helper */
1977 helper = g_slice_new0 (XFerMsgAsyncHelper);
1978 helper->mail_op = g_object_ref (self);
1979 helper->dest_folder = NULL;
1980 helper->headers = NULL;
1981 helper->user_callback = user_callback;
1982 helper->user_data = user_data;
1984 /* Move/Copy folder */
1985 modest_mail_operation_notify_start (self);
1986 tny_folder_copy_async (folder,
1988 tny_folder_get_name (folder),
1991 transfer_folder_status_cb,
1997 /* Set status failed and set an error */
1998 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1999 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2000 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2003 /* Call the user callback if exists */
2005 user_callback (self, user_data);
2007 /* Notify the queue */
2008 modest_mail_operation_notify_end (self);
2012 modest_mail_operation_rename_folder (ModestMailOperation *self,
2016 ModestMailOperationPrivate *priv;
2017 ModestTnyFolderRules rules;
2018 XFerMsgAsyncHelper *helper;
2020 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2021 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2022 g_return_if_fail (name);
2024 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2026 /* Get account and set it into mail_operation */
2027 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2028 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2030 /* Check folder rules */
2031 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2032 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2033 /* Set status failed and set an error */
2034 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2035 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2036 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2037 _("FIXME: unable to rename"));
2039 /* Notify about operation end */
2040 modest_mail_operation_notify_end (self);
2041 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2042 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2043 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2044 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2045 _("FIXME: unable to rename"));
2046 /* Notify about operation end */
2047 modest_mail_operation_notify_end (self);
2049 TnyFolderStore *into;
2051 into = tny_folder_get_folder_store (folder);
2053 /* Check that the new folder name is not used by any
2054 special local folder */
2055 if (new_name_valid_if_local_account (priv, into, name)) {
2056 /* Create the helper */
2057 helper = g_slice_new0 (XFerMsgAsyncHelper);
2058 helper->mail_op = g_object_ref(self);
2059 helper->dest_folder = NULL;
2060 helper->headers = NULL;
2061 helper->user_callback = NULL;
2062 helper->user_data = NULL;
2064 /* Rename. Camel handles folder subscription/unsubscription */
2065 modest_mail_operation_notify_start (self);
2066 tny_folder_copy_async (folder, into, name, TRUE,
2068 transfer_folder_status_cb,
2071 modest_mail_operation_notify_end (self);
2073 g_object_unref (into);
2077 /* ******************************************************************* */
2078 /* ************************** MSG ACTIONS ************************* */
2079 /* ******************************************************************* */
2082 modest_mail_operation_get_msg (ModestMailOperation *self,
2084 GetMsgAsyncUserCallback user_callback,
2087 GetMsgInfo *helper = NULL;
2089 ModestMailOperationPrivate *priv;
2091 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2092 g_return_if_fail (TNY_IS_HEADER (header));
2094 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2095 folder = tny_header_get_folder (header);
2097 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2098 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2102 /* Get account and set it into mail_operation */
2103 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2105 /* Check for cached messages */
2106 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2107 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2109 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2111 /* Create the helper */
2112 helper = g_slice_new0 (GetMsgInfo);
2113 helper->header = g_object_ref (header);
2114 helper->mail_op = g_object_ref (self);
2115 helper->user_callback = user_callback;
2116 helper->user_data = user_data;
2117 helper->destroy_notify = NULL;
2118 helper->last_total_bytes = 0;
2119 helper->sum_total_bytes = 0;
2120 helper->total_bytes = tny_header_get_message_size (header);
2122 modest_mail_operation_notify_start (self);
2123 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2125 g_object_unref (G_OBJECT (folder));
2129 get_msg_status_cb (GObject *obj,
2133 GetMsgInfo *helper = NULL;
2135 g_return_if_fail (status != NULL);
2136 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2138 helper = (GetMsgInfo *) user_data;
2139 g_return_if_fail (helper != NULL);
2141 /* Notify progress */
2142 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2143 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2147 get_msg_async_cb (TnyFolder *folder,
2153 GetMsgInfo *info = NULL;
2154 ModestMailOperationPrivate *priv = NULL;
2157 info = (GetMsgInfo *) user_data;
2159 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2161 finished = (priv->done == priv->total) ? TRUE : FALSE;
2164 if (canceled || err) {
2165 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2167 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2168 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2171 /* Set the success status before calling the user callback */
2172 if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2173 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2177 /* Call the user callback */
2178 if (info->user_callback)
2179 info->user_callback (info->mail_op, info->header, canceled,
2180 msg, err, info->user_data);
2182 /* Notify about operation end if this is the last callback */
2184 /* Free user data */
2185 if (info->destroy_notify)
2186 info->destroy_notify (info->user_data);
2188 /* Notify about operation end */
2189 modest_mail_operation_notify_end (info->mail_op);
2193 g_object_unref (info->header);
2194 g_object_unref (info->mail_op);
2195 g_slice_free (GetMsgInfo, info);
2199 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2200 TnyList *header_list,
2201 GetMsgAsyncUserCallback user_callback,
2203 GDestroyNotify notify)
2205 ModestMailOperationPrivate *priv = NULL;
2206 gboolean size_ok = TRUE;
2208 TnyIterator *iter = NULL;
2210 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2212 /* Init mail operation */
2213 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2214 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2215 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2217 priv->total = tny_list_get_length(header_list);
2219 /* Get account and set it into mail_operation */
2220 if (tny_list_get_length (header_list) >= 1) {
2221 iter = tny_list_create_iterator (header_list);
2222 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2224 TnyFolder *folder = tny_header_get_folder (header);
2226 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2227 g_object_unref (folder);
2229 g_object_unref (header);
2232 if (tny_list_get_length (header_list) == 1) {
2233 g_object_unref (iter);
2238 /* Get msg size limit */
2239 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2240 MODEST_CONF_MSG_SIZE_LIMIT,
2243 g_clear_error (&(priv->error));
2244 max_size = G_MAXINT;
2246 max_size = max_size * KB;
2249 /* Check message size limits. If there is only one message
2250 always retrieve it */
2252 while (!tny_iterator_is_done (iter) && size_ok) {
2253 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2255 if (tny_header_get_message_size (header) >= max_size)
2257 g_object_unref (header);
2260 tny_iterator_next (iter);
2262 g_object_unref (iter);
2266 modest_mail_operation_notify_start (self);
2268 iter = tny_list_create_iterator (header_list);
2269 while (!tny_iterator_is_done (iter)) {
2270 GetMsgInfo *msg_info = NULL;
2271 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2272 TnyFolder *folder = tny_header_get_folder (header);
2274 /* Create the message info */
2275 msg_info = g_slice_new0 (GetMsgInfo);
2276 msg_info->mail_op = g_object_ref (self);
2277 msg_info->header = g_object_ref (header);
2278 msg_info->user_callback = user_callback;
2279 msg_info->user_data = user_data;
2280 msg_info->destroy_notify = notify;
2281 msg_info->last_total_bytes = 0;
2282 msg_info->sum_total_bytes = 0;
2283 msg_info->total_bytes = compute_message_list_size (header_list);
2285 /* The callback will call it per each header */
2286 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2288 /* Free and go on */
2289 g_object_unref (header);
2290 g_object_unref (folder);
2291 tny_iterator_next (iter);
2293 g_object_unref (iter);
2295 /* Set status failed and set an error */
2296 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2297 /* FIXME: the error msg is different for pop */
2298 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2299 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2300 _("emev_ni_ui_imap_msg_size_exceed_error"));
2301 /* Remove from queue and free resources */
2302 modest_mail_operation_notify_end (self);
2310 modest_mail_operation_remove_msg (ModestMailOperation *self,
2312 gboolean remove_to_trash /*ignored*/)
2315 ModestMailOperationPrivate *priv;
2317 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2318 g_return_if_fail (TNY_IS_HEADER (header));
2320 if (remove_to_trash)
2321 g_warning ("remove to trash is not implemented");
2323 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2324 folder = tny_header_get_folder (header);
2326 /* Get account and set it into mail_operation */
2327 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2328 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2329 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2331 /* remove message from folder */
2332 tny_folder_remove_msg (folder, header, &(priv->error));
2334 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2335 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2337 modest_mail_operation_notify_start (self);
2339 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2340 TNY_IS_CAMEL_POP_FOLDER (folder))
2341 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> dont expunge */
2343 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2349 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2351 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2354 g_object_unref (G_OBJECT (folder));
2356 /* Notify about operation end */
2357 modest_mail_operation_notify_end (self);
2361 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2363 gboolean remove_to_trash /*ignored*/)
2366 ModestMailOperationPrivate *priv;
2367 TnyIterator *iter = NULL;
2368 TnyHeader *header = NULL;
2369 TnyList *remove_headers = NULL;
2370 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2372 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2373 g_return_if_fail (TNY_IS_LIST (headers));
2375 if (remove_to_trash)
2376 g_warning ("remove to trash is not implemented");
2378 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2380 remove_headers = g_object_ref(headers);
2382 /* Get folder from first header and sync it */
2383 iter = tny_list_create_iterator (headers);
2384 header = TNY_HEADER (tny_iterator_get_current (iter));
2385 folder = tny_header_get_folder (header);
2387 /* Don't remove messages that are being sent */
2388 if (modest_tny_folder_is_local_folder (folder)) {
2389 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2391 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2392 TnyTransportAccount *traccount = NULL;
2393 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2394 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2396 ModestTnySendQueueStatus status;
2397 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2398 TnyIterator *iter = tny_list_create_iterator(headers);
2399 g_object_unref(remove_headers);
2400 remove_headers = TNY_LIST(tny_simple_list_new());
2401 while (!tny_iterator_is_done(iter)) {
2403 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2404 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2405 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2406 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2407 tny_list_append(remove_headers, G_OBJECT(hdr));
2409 g_object_unref(hdr);
2411 tny_iterator_next(iter);
2413 g_object_unref(iter);
2414 g_object_unref(traccount);
2418 /* Get account and set it into mail_operation */
2419 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2420 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2421 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2423 /* remove message from folder */
2424 modest_mail_operation_notify_start (self);
2426 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2428 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2429 TNY_IS_CAMEL_POP_FOLDER (folder))
2430 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> don't expunge */
2433 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2439 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2441 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2444 g_object_unref (remove_headers);
2445 g_object_unref (header);
2446 g_object_unref (iter);
2447 g_object_unref (G_OBJECT (folder));
2449 /* Notify about operation end */
2450 modest_mail_operation_notify_end (self);
2454 notify_progress_of_multiple_messages (ModestMailOperation *self,
2456 gint *last_total_bytes,
2457 gint *sum_total_bytes,
2459 gboolean increment_done)
2461 ModestMailOperationPrivate *priv;
2462 ModestMailOperationState *state;
2463 gboolean is_num_bytes;
2465 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2467 /* We know that tinymail sends us information about
2468 transferred bytes with this particular message */
2469 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2471 state = modest_mail_operation_clone_state (self);
2472 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2473 /* We know that we're in a different message when the
2474 total number of bytes to transfer is different. Of
2475 course it could fail if we're transferring messages
2476 of the same size, but this is a workarround */
2477 if (status->of_total != *last_total_bytes) {
2478 /* We need to increment the done when there is
2479 no information about each individual
2480 message, we need to do this in message
2481 transfers, and we don't do it for getting
2485 *sum_total_bytes += *last_total_bytes;
2486 *last_total_bytes = status->of_total;
2488 state->bytes_done += status->position + *sum_total_bytes;
2489 state->bytes_total = total_bytes;
2491 /* Notify the status change. Only notify about changes
2492 referred to bytes */
2493 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2497 g_slice_free (ModestMailOperationState, state);
2501 transfer_msgs_status_cb (GObject *obj,
2505 XFerMsgAsyncHelper *helper;
2507 g_return_if_fail (status != NULL);
2508 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2510 helper = (XFerMsgAsyncHelper *) user_data;
2511 g_return_if_fail (helper != NULL);
2513 /* Notify progress */
2514 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2515 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2520 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2522 XFerMsgAsyncHelper *helper;
2523 ModestMailOperation *self;
2524 ModestMailOperationPrivate *priv;
2525 TnyIterator *iter = NULL;
2526 TnyHeader *header = NULL;
2528 helper = (XFerMsgAsyncHelper *) user_data;
2529 self = helper->mail_op;
2531 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2534 priv->error = g_error_copy (err);
2536 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2537 } else if (cancelled) {
2538 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2539 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2540 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2541 _("Error trying to refresh the contents of %s"),
2542 tny_folder_get_name (folder));
2545 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2547 /* Update folder counts */
2548 tny_folder_poke_status (folder);
2549 tny_folder_poke_status (helper->dest_folder);
2553 /* Mark headers as deleted and seen */
2554 if ((helper->delete) &&
2555 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2556 iter = tny_list_create_iterator (helper->headers);
2557 while (!tny_iterator_is_done (iter)) {
2558 header = TNY_HEADER (tny_iterator_get_current (iter));
2559 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2560 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2561 g_object_unref (header);
2563 tny_iterator_next (iter);
2569 /* Notify about operation end */
2570 modest_mail_operation_notify_end (self);
2572 /* If user defined callback function was defined, call it */
2573 if (helper->user_callback) {
2574 /* This is not a GDK lock because we are a Tinymail callback and
2575 * Tinymail already acquires the Gdk lock */
2577 /* no gdk_threads_enter (), CHECKED */
2578 helper->user_callback (self, helper->user_data);
2579 /* no gdk_threads_leave (), CHECKED */
2583 if (helper->headers)
2584 g_object_unref (helper->headers);
2585 if (helper->dest_folder)
2586 g_object_unref (helper->dest_folder);
2587 if (helper->mail_op)
2588 g_object_unref (helper->mail_op);
2590 g_object_unref (folder);
2592 g_object_unref (iter);
2593 g_slice_free (XFerMsgAsyncHelper, helper);
2597 compute_message_list_size (TnyList *headers)
2602 iter = tny_list_create_iterator (headers);
2603 while (!tny_iterator_is_done (iter)) {
2604 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2605 size += tny_header_get_message_size (header);
2606 g_object_unref (header);
2607 tny_iterator_next (iter);
2609 g_object_unref (iter);
2615 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2618 gboolean delete_original,
2619 XferAsyncUserCallback user_callback,
2622 ModestMailOperationPrivate *priv = NULL;
2623 TnyIterator *iter = NULL;
2624 TnyFolder *src_folder = NULL;
2625 XFerMsgAsyncHelper *helper = NULL;
2626 TnyHeader *header = NULL;
2627 ModestTnyFolderRules rules = 0;
2629 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2630 g_return_if_fail (headers && TNY_IS_LIST (headers));
2631 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2633 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2634 priv->total = tny_list_get_length (headers);
2636 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2637 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2639 /* Apply folder rules */
2640 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2641 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2642 /* Set status failed and set an error */
2643 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2644 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2645 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2646 _CS("ckct_ib_unable_to_paste_here"));
2647 /* Notify the queue */
2648 modest_mail_operation_notify_end (self);
2652 /* Get source folder */
2653 iter = tny_list_create_iterator (headers);
2654 header = TNY_HEADER (tny_iterator_get_current (iter));
2656 src_folder = tny_header_get_folder (header);
2657 g_object_unref (header);
2659 g_object_unref (iter);
2661 if (src_folder == NULL) {
2662 /* Notify the queue */
2663 modest_mail_operation_notify_end (self);
2665 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2670 /* Check folder source and destination */
2671 if (src_folder == folder) {
2672 /* Set status failed and set an error */
2673 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2674 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2675 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2676 _("mcen_ib_unable_to_copy_samefolder"));
2678 /* Notify the queue */
2679 modest_mail_operation_notify_end (self);
2682 g_object_unref (src_folder);
2686 /* Create the helper */
2687 helper = g_slice_new0 (XFerMsgAsyncHelper);
2688 helper->mail_op = g_object_ref(self);
2689 helper->dest_folder = g_object_ref(folder);
2690 helper->headers = g_object_ref(headers);
2691 helper->user_callback = user_callback;
2692 helper->user_data = user_data;
2693 helper->delete = delete_original;
2694 helper->last_total_bytes = 0;
2695 helper->sum_total_bytes = 0;
2696 helper->total_bytes = compute_message_list_size (headers);
2698 /* Get account and set it into mail_operation */
2699 priv->account = modest_tny_folder_get_account (src_folder);
2701 /* Transfer messages */
2702 modest_mail_operation_notify_start (self);
2703 tny_folder_transfer_msgs_async (src_folder,
2708 transfer_msgs_status_cb,
2714 on_refresh_folder (TnyFolder *folder,
2719 RefreshAsyncHelper *helper = NULL;
2720 ModestMailOperation *self = NULL;
2721 ModestMailOperationPrivate *priv = NULL;
2723 helper = (RefreshAsyncHelper *) user_data;
2724 self = helper->mail_op;
2725 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2727 g_return_if_fail(priv!=NULL);
2730 priv->error = g_error_copy (error);
2731 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2736 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2737 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2738 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2739 _("Error trying to refresh the contents of %s"),
2740 tny_folder_get_name (folder));
2744 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2747 /* Call user defined callback, if it exists */
2748 if (helper->user_callback) {
2750 /* This is not a GDK lock because we are a Tinymail callback and
2751 * Tinymail already acquires the Gdk lock */
2752 helper->user_callback (self, folder, helper->user_data);
2756 g_slice_free (RefreshAsyncHelper, helper);
2758 /* Notify about operation end */
2759 modest_mail_operation_notify_end (self);
2760 g_object_unref(self);
2764 on_refresh_folder_status_update (GObject *obj,
2768 RefreshAsyncHelper *helper = NULL;
2769 ModestMailOperation *self = NULL;
2770 ModestMailOperationPrivate *priv = NULL;
2771 ModestMailOperationState *state;
2773 g_return_if_fail (user_data != NULL);
2774 g_return_if_fail (status != NULL);
2775 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2777 helper = (RefreshAsyncHelper *) user_data;
2778 self = helper->mail_op;
2779 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2781 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2783 priv->done = status->position;
2784 priv->total = status->of_total;
2786 state = modest_mail_operation_clone_state (self);
2788 /* This is not a GDK lock because we are a Tinymail callback and
2789 * Tinymail already acquires the Gdk lock */
2790 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2792 g_slice_free (ModestMailOperationState, state);
2796 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2798 RefreshAsyncUserCallback user_callback,
2801 ModestMailOperationPrivate *priv = NULL;
2802 RefreshAsyncHelper *helper = NULL;
2804 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2806 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2808 /* Get account and set it into mail_operation */
2809 priv->account = modest_tny_folder_get_account (folder);
2810 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2812 /* Create the helper */
2813 helper = g_slice_new0 (RefreshAsyncHelper);
2814 helper->mail_op = g_object_ref(self);
2815 helper->user_callback = user_callback;
2816 helper->user_data = user_data;
2818 /* Refresh the folder. TODO: tinymail could issue a status
2819 updates before the callback call then this could happen. We
2820 must review the design */
2821 modest_mail_operation_notify_start (self);
2822 tny_folder_refresh_async (folder,
2824 on_refresh_folder_status_update,
2830 modest_mail_operation_notify_start (ModestMailOperation *self)
2832 ModestMailOperationPrivate *priv = NULL;
2834 g_return_if_fail (self);
2836 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2838 /* Ensure that all the fields are filled correctly */
2839 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
2841 /* Notify the observers about the mail operation. We do not
2842 wrapp this emission because we assume that this function is
2843 always called from within the main lock */
2844 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
2849 * It's used by the mail operation queue to notify the observers
2850 * attached to that signal that the operation finished. We need to use
2851 * that because tinymail does not give us the progress of a given
2852 * operation when it finishes (it directly calls the operation
2856 modest_mail_operation_notify_end (ModestMailOperation *self)
2858 ModestMailOperationPrivate *priv = NULL;
2860 g_return_if_fail (self);
2862 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2864 /* Notify the observers about the mail operation end. We do
2865 not wrapp this emission because we assume that this
2866 function is always called from within the main lock */
2867 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
2869 /* Remove the error user data */
2870 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
2871 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
2875 modest_mail_operation_get_account (ModestMailOperation *self)
2877 ModestMailOperationPrivate *priv = NULL;
2879 g_return_val_if_fail (self, NULL);
2881 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2883 return (priv->account) ? g_object_ref (priv->account) : NULL;
2887 modest_mail_operation_noop (ModestMailOperation *self)
2889 ModestMailOperationPrivate *priv = NULL;
2891 g_return_if_fail (self);
2893 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2894 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2895 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2899 /* This mail operation does nothing actually */
2900 modest_mail_operation_notify_start (self);
2901 modest_mail_operation_notify_end (self);