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,
666 TnyHeaderFlags flags = 0;
668 /* Set priority flags in message */
669 header = tny_msg_get_header (new_msg);
670 if (info->priority_flags != 0)
671 flags |= info->priority_flags;
673 /* Set attachment flags in message */
674 if (info->attachments_list != NULL)
675 flags |= TNY_HEADER_FLAG_ATTACHMENTS;
677 tny_header_set_flag (header, flags);
678 g_object_unref (G_OBJECT(header));
680 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
681 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
682 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
683 "modest: failed to create a new msg\n");
691 g_free (info->plain_body);
692 g_free (info->html_body);
693 g_free (info->subject);
694 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
695 g_list_free (info->attachments_list);
696 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
697 g_list_free (info->images_list);
699 if (info->callback) {
700 CreateMsgIdleInfo *idle_info;
701 idle_info = g_slice_new0 (CreateMsgIdleInfo);
702 idle_info->mail_op = g_object_ref (info->mail_op);
703 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
704 idle_info->callback = info->callback;
705 idle_info->userdata = info->userdata;
706 g_idle_add (idle_create_msg_cb, idle_info);
708 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
711 g_object_unref (info->mail_op);
712 g_slice_free (CreateMsgInfo, info);
717 modest_mail_operation_create_msg (ModestMailOperation *self,
718 const gchar *from, const gchar *to,
719 const gchar *cc, const gchar *bcc,
720 const gchar *subject, const gchar *plain_body,
721 const gchar *html_body,
722 const GList *attachments_list,
723 const GList *images_list,
724 TnyHeaderFlags priority_flags,
725 ModestMailOperationCreateMsgCallback callback,
728 CreateMsgInfo *info = NULL;
730 info = g_slice_new0 (CreateMsgInfo);
731 info->mail_op = g_object_ref (self);
733 info->from = g_strdup (from);
734 info->to = g_strdup (to);
735 info->cc = g_strdup (cc);
736 info->bcc = g_strdup (bcc);
737 info->subject = g_strdup (subject);
738 info->plain_body = g_strdup (plain_body);
739 info->html_body = g_strdup (html_body);
740 info->attachments_list = g_list_copy ((GList *) attachments_list);
741 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
742 info->images_list = g_list_copy ((GList *) images_list);
743 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
744 info->priority_flags = priority_flags;
746 info->callback = callback;
747 info->userdata = userdata;
749 g_thread_create (create_msg_thread, info, FALSE, NULL);
754 TnyTransportAccount *transport_account;
759 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
763 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
764 TnyFolder *draft_folder = NULL;
765 TnyFolder *outbox_folder = NULL;
773 /* Call mail operation */
774 modest_mail_operation_send_mail (self, info->transport_account, msg);
776 /* Remove old mail from its source folder */
777 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
778 TNY_FOLDER_TYPE_DRAFTS);
779 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
780 TNY_FOLDER_TYPE_OUTBOX);
781 if (info->draft_msg != NULL) {
782 TnyFolder *folder = NULL;
783 TnyFolder *src_folder = NULL;
784 TnyFolderType folder_type;
785 folder = tny_msg_get_folder (info->draft_msg);
786 if (folder == NULL) goto end;
787 folder_type = modest_tny_folder_guess_folder_type (folder);
789 if (folder_type == TNY_FOLDER_TYPE_INVALID)
790 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
792 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
793 src_folder = outbox_folder;
795 src_folder = draft_folder;
797 /* Note: This can fail (with a warning) if the message is not really already in a folder,
798 * because this function requires it to have a UID. */
799 header = tny_msg_get_header (info->draft_msg);
800 tny_folder_remove_msg (src_folder, header, NULL);
802 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
803 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
805 g_object_unref (header);
806 g_object_unref (folder);
813 g_object_unref (info->draft_msg);
815 g_object_unref (draft_folder);
817 g_object_unref (outbox_folder);
818 if (info->transport_account)
819 g_object_unref (info->transport_account);
820 g_slice_free (SendNewMailInfo, info);
821 modest_mail_operation_notify_end (self);
825 modest_mail_operation_send_new_mail (ModestMailOperation *self,
826 TnyTransportAccount *transport_account,
828 const gchar *from, const gchar *to,
829 const gchar *cc, const gchar *bcc,
830 const gchar *subject, const gchar *plain_body,
831 const gchar *html_body,
832 const GList *attachments_list,
833 const GList *images_list,
834 TnyHeaderFlags priority_flags)
836 ModestMailOperationPrivate *priv = NULL;
837 SendNewMailInfo *info;
839 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
840 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
842 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
843 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
844 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
846 /* Check parametters */
848 /* Set status failed and set an error */
849 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
850 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
851 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
852 _("Error trying to send a mail. You need to set at least one recipient"));
855 info = g_slice_new0 (SendNewMailInfo);
856 info->transport_account = transport_account;
857 if (transport_account)
858 g_object_ref (transport_account);
859 info->draft_msg = draft_msg;
861 g_object_ref (draft_msg);
864 modest_mail_operation_notify_start (self);
865 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
866 attachments_list, images_list, priority_flags,
867 modest_mail_operation_send_new_mail_cb, info);
873 TnyTransportAccount *transport_account;
875 SaveToDraftstCallback callback;
879 ModestMailOperation *mailop;
880 } SaveToDraftsAddMsgInfo;
883 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
888 ModestMailOperationPrivate *priv = NULL;
889 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
891 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
894 g_warning ("%s: priv->error != NULL", __FUNCTION__);
895 g_error_free(priv->error);
898 priv->error = (err == NULL) ? NULL : g_error_copy(err);
900 if ((!priv->error) && (info->draft_msg != NULL)) {
901 TnyHeader *header = tny_msg_get_header (info->draft_msg);
902 TnyFolder *src_folder = tny_header_get_folder (header);
904 /* Remove the old draft */
905 tny_folder_remove_msg (src_folder, header, NULL);
907 /* Synchronize to expunge and to update the msg counts */
908 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
909 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
911 g_object_unref (G_OBJECT(header));
912 g_object_unref (G_OBJECT(src_folder));
916 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
918 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
920 /* Call the user callback */
922 info->callback (info->mailop, info->msg, info->user_data);
924 if (info->transport_account)
925 g_object_unref (G_OBJECT(info->transport_account));
927 g_object_unref (G_OBJECT (info->draft_msg));
929 g_object_unref (G_OBJECT(info->drafts));
931 g_object_unref (G_OBJECT (info->msg));
932 g_slice_free (SaveToDraftsAddMsgInfo, info);
934 modest_mail_operation_notify_end (info->mailop);
935 g_object_unref(info->mailop);
940 TnyTransportAccount *transport_account;
942 SaveToDraftstCallback callback;
947 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
951 TnyFolder *drafts = NULL;
952 ModestMailOperationPrivate *priv = NULL;
953 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
955 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
958 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
959 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
960 "modest: failed to create a new msg\n");
962 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
963 TNY_FOLDER_TYPE_DRAFTS);
965 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
966 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
967 "modest: failed to create a new msg\n");
972 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
973 cb_info->transport_account = g_object_ref(info->transport_account);
974 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
975 cb_info->callback = info->callback;
976 cb_info->user_data = info->user_data;
977 cb_info->drafts = g_object_ref(drafts);
978 cb_info->msg = g_object_ref(msg);
979 cb_info->mailop = g_object_ref(self);
980 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
983 /* Call the user callback */
984 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
986 info->callback (self, msg, info->user_data);
987 modest_mail_operation_notify_end (self);
991 g_object_unref (G_OBJECT(drafts));
993 g_object_unref (G_OBJECT (info->draft_msg));
994 if (info->transport_account)
995 g_object_unref (G_OBJECT(info->transport_account));
996 g_slice_free (SaveToDraftsInfo, info);
1000 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1001 TnyTransportAccount *transport_account,
1003 const gchar *from, const gchar *to,
1004 const gchar *cc, const gchar *bcc,
1005 const gchar *subject, const gchar *plain_body,
1006 const gchar *html_body,
1007 const GList *attachments_list,
1008 const GList *images_list,
1009 TnyHeaderFlags priority_flags,
1010 SaveToDraftstCallback callback,
1013 ModestMailOperationPrivate *priv = NULL;
1014 SaveToDraftsInfo *info = NULL;
1016 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1017 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1019 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1021 /* Get account and set it into mail_operation */
1022 priv->account = g_object_ref (transport_account);
1023 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1025 info = g_slice_new0 (SaveToDraftsInfo);
1026 info->transport_account = g_object_ref (transport_account);
1027 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1028 info->callback = callback;
1029 info->user_data = user_data;
1031 modest_mail_operation_notify_start (self);
1032 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1033 attachments_list, images_list, priority_flags,
1034 modest_mail_operation_save_to_drafts_cb, info);
1039 ModestMailOperation *mail_op;
1040 TnyStoreAccount *account;
1041 TnyTransportAccount *transport_account;
1043 gint retrieve_limit;
1044 gchar *retrieve_type;
1045 gchar *account_name;
1046 UpdateAccountCallback callback;
1048 TnyList *new_headers;
1049 } UpdateAccountInfo;
1053 ModestMailOperation *mail_op;
1054 TnyMimePart *mime_part;
1056 GetMimePartSizeCallback callback;
1058 } GetMimePartSizeInfo;
1060 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1061 /* We use this folder observer to track the headers that have been
1062 * added to a folder */
1065 TnyList *new_headers;
1066 } InternalFolderObserver;
1069 GObjectClass parent;
1070 } InternalFolderObserverClass;
1072 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1074 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1075 internal_folder_observer,
1077 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1081 foreach_add_item (gpointer header, gpointer user_data)
1083 tny_list_prepend (TNY_LIST (user_data),
1084 g_object_ref (G_OBJECT (header)));
1087 /* This is the method that looks for new messages in a folder */
1089 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1091 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1093 TnyFolderChangeChanged changed;
1095 changed = tny_folder_change_get_changed (change);
1097 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1100 /* Get added headers */
1101 list = tny_simple_list_new ();
1102 tny_folder_change_get_added_headers (change, list);
1104 /* Add them to the folder observer */
1105 tny_list_foreach (list, foreach_add_item,
1106 derived->new_headers);
1108 g_object_unref (G_OBJECT (list));
1113 internal_folder_observer_init (InternalFolderObserver *self)
1115 self->new_headers = tny_simple_list_new ();
1118 internal_folder_observer_finalize (GObject *object)
1120 InternalFolderObserver *self;
1122 self = (InternalFolderObserver *) object;
1123 g_object_unref (self->new_headers);
1125 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1128 tny_folder_observer_init (TnyFolderObserverIface *iface)
1130 iface->update_func = internal_folder_observer_update;
1133 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1135 GObjectClass *object_class;
1137 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1138 object_class = (GObjectClass*) klass;
1139 object_class->finalize = internal_folder_observer_finalize;
1145 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
1148 TnyList *folders = tny_simple_list_new ();
1150 tny_folder_store_get_folders (store, folders, query, NULL);
1151 iter = tny_list_create_iterator (folders);
1153 while (!tny_iterator_is_done (iter)) {
1155 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1157 tny_list_prepend (all_folders, G_OBJECT (folder));
1158 recurse_folders (folder, query, all_folders);
1159 g_object_unref (G_OBJECT (folder));
1162 tny_iterator_next (iter);
1164 g_object_unref (G_OBJECT (iter));
1165 g_object_unref (G_OBJECT (folders));
1169 * Issues the "progress-changed" signal. The timer won't be removed,
1170 * so you must call g_source_remove to stop the signal emission
1173 idle_notify_progress (gpointer data)
1175 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1176 ModestMailOperationState *state;
1178 state = modest_mail_operation_clone_state (mail_op);
1180 /* This is a GDK lock because we are an idle callback and
1181 * the handlers of this signal can contain Gtk+ code */
1183 gdk_threads_enter (); /* CHECKED */
1184 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1185 gdk_threads_leave (); /* CHECKED */
1187 g_slice_free (ModestMailOperationState, state);
1193 * Issues the "progress-changed" signal and removes the timer. It uses
1194 * a lock to ensure that the progress information of the mail
1195 * operation is not modified while there are notifications pending
1198 idle_notify_progress_once (gpointer data)
1202 pair = (ModestPair *) data;
1204 /* This is a GDK lock because we are an idle callback and
1205 * the handlers of this signal can contain Gtk+ code */
1207 gdk_threads_enter (); /* CHECKED */
1208 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1209 gdk_threads_leave (); /* CHECKED */
1211 /* Free the state and the reference to the mail operation */
1212 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1213 g_object_unref (pair->first);
1219 * Used to notify the queue from the main
1220 * loop. We call it inside an idle call to achieve that
1223 idle_notify_queue (gpointer data)
1225 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1227 gdk_threads_enter ();
1228 modest_mail_operation_notify_end (mail_op);
1229 gdk_threads_leave ();
1230 g_object_unref (mail_op);
1236 compare_headers_by_date (gconstpointer a,
1239 TnyHeader **header1, **header2;
1240 time_t sent1, sent2;
1242 header1 = (TnyHeader **) a;
1243 header2 = (TnyHeader **) b;
1245 sent1 = tny_header_get_date_sent (*header1);
1246 sent2 = tny_header_get_date_sent (*header2);
1248 /* We want the most recent ones (greater time_t) at the
1257 set_last_updated_idle (gpointer data)
1260 /* This is a GDK lock because we are an idle callback and
1261 * modest_account_mgr_set_last_updated can issue Gtk+ code */
1263 gdk_threads_enter (); /* CHECKED - please recheck */
1265 /* It does not matter if the time is not exactly the same than
1266 the time when this idle was called, it's just an
1267 approximation and it won't be very different */
1269 modest_account_mgr_set_last_updated (modest_runtime_get_account_mgr (),
1273 gdk_threads_leave (); /* CHECKED - please recheck */
1279 idle_update_account_cb (gpointer data)
1281 UpdateAccountInfo *idle_info;
1283 idle_info = (UpdateAccountInfo *) data;
1285 /* This is a GDK lock because we are an idle callback and
1286 * idle_info->callback can contain Gtk+ code */
1288 gdk_threads_enter (); /* CHECKED */
1289 idle_info->callback (idle_info->mail_op,
1290 idle_info->new_headers,
1291 idle_info->user_data);
1292 gdk_threads_leave (); /* CHECKED */
1295 g_object_unref (idle_info->mail_op);
1296 if (idle_info->new_headers)
1297 g_object_unref (idle_info->new_headers);
1304 get_all_folders_from_account (TnyStoreAccount *account,
1307 TnyList *all_folders = NULL;
1308 TnyIterator *iter = NULL;
1309 TnyFolderStoreQuery *query = NULL;
1311 all_folders = tny_simple_list_new ();
1312 query = tny_folder_store_query_new ();
1313 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1314 tny_folder_store_get_folders (TNY_FOLDER_STORE (account),
1321 g_object_unref (all_folders);
1325 iter = tny_list_create_iterator (all_folders);
1326 while (!tny_iterator_is_done (iter)) {
1327 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1329 recurse_folders (folder, query, all_folders);
1330 g_object_unref (folder);
1332 tny_iterator_next (iter);
1334 g_object_unref (G_OBJECT (iter));
1341 update_account_thread (gpointer thr_user_data)
1343 static gboolean first_time = TRUE;
1344 UpdateAccountInfo *info = NULL;
1345 TnyList *all_folders = NULL, *new_headers = NULL;
1346 GPtrArray *new_headers_array = NULL;
1347 TnyIterator *iter = NULL;
1348 ModestMailOperationPrivate *priv = NULL;
1349 ModestTnySendQueue *send_queue = NULL;
1350 gint i = 0, timeout = 0;
1352 info = (UpdateAccountInfo *) thr_user_data;
1353 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1355 /* Get account and set it into mail_operation */
1356 priv->account = g_object_ref (info->account);
1358 /* Get all the folders. We can do it synchronously because
1359 we're already running in a different thread than the UI */
1360 all_folders = get_all_folders_from_account (info->account, &(priv->error));
1362 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1366 /* Update status and notify. We need to call the notification
1367 with a source function in order to call it from the main
1368 loop. We need that in order not to get into trouble with
1369 Gtk+. We use a timeout in order to provide more status
1370 information, because the sync tinymail call does not
1371 provide it for the moment */
1372 timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1374 new_headers_array = g_ptr_array_new ();
1375 iter = tny_list_create_iterator (all_folders);
1377 while (!tny_iterator_is_done (iter) && !priv->error &&
1378 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1380 TnyFolderType folder_type;
1381 TnyFolder *folder = NULL;
1383 folder = TNY_FOLDER (tny_iterator_get_current (iter));
1384 folder_type = tny_folder_get_folder_type (folder);
1386 /* Refresh it only if it's the INBOX */
1387 if (folder_type == TNY_FOLDER_TYPE_INBOX) {
1388 InternalFolderObserver *observer = NULL;
1389 TnyIterator *new_headers_iter = NULL;
1391 /* Refresh the folder. Our observer receives
1392 * the new emails during folder refreshes, so
1393 * we can use observer->new_headers
1395 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1396 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1398 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1400 new_headers_iter = tny_list_create_iterator (observer->new_headers);
1401 while (!tny_iterator_is_done (new_headers_iter)) {
1402 TnyHeader *header = NULL;
1404 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1405 /* Apply per-message size limits */
1406 if (tny_header_get_message_size (header) < info->max_size)
1407 g_ptr_array_add (new_headers_array, g_object_ref (header));
1409 g_object_unref (header);
1410 tny_iterator_next (new_headers_iter);
1412 g_object_unref (new_headers_iter);
1414 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1415 g_object_unref (observer);
1417 /* We no not need to do it the first time,
1418 because it's automatically done by the tree
1420 if (G_LIKELY (!first_time))
1421 tny_folder_poke_status (folder);
1423 g_object_unref (folder);
1425 tny_iterator_next (iter);
1427 g_object_unref (G_OBJECT (iter));
1428 g_source_remove (timeout);
1430 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1431 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1432 new_headers_array->len > 0) {
1436 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1438 /* TODO: Ask the user, instead of just failing,
1439 * showing mail_nc_msg_count_limit_exceeded, with 'Get
1440 * all' and 'Newest only' buttons. */
1441 if (new_headers_array->len > info->retrieve_limit) {
1445 /* Should be get only the headers or the message as well? */
1446 if (g_ascii_strcasecmp (info->retrieve_type,
1447 MODEST_ACCOUNT_RETRIEVE_VALUE_HEADERS_ONLY) != 0) {
1449 priv->total = MIN (new_headers_array->len, info->retrieve_limit);
1450 while (msg_num < priv->total) {
1452 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1453 TnyFolder *folder = tny_header_get_folder (header);
1454 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1455 ModestMailOperationState *state;
1459 /* We can not just use the mail operation because the
1460 values of done and total could change before the
1462 state = modest_mail_operation_clone_state (info->mail_op);
1463 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1464 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1465 pair, (GDestroyNotify) modest_pair_free);
1467 g_object_unref (msg);
1468 g_object_unref (folder);
1475 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1478 /* Copy the headers to a list and free the array */
1479 new_headers = tny_simple_list_new ();
1480 for (i=0; i < new_headers_array->len; i++) {
1481 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1482 tny_list_append (new_headers, G_OBJECT (header));
1484 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1485 g_ptr_array_free (new_headers_array, FALSE);
1488 /* Perform send (if operation was not cancelled) */
1491 if (priv->account != NULL)
1492 g_object_unref (priv->account);
1494 if (info->transport_account) {
1495 priv->account = g_object_ref (info->transport_account);
1497 send_queue = modest_runtime_get_send_queue (info->transport_account);
1499 modest_tny_send_queue_try_to_send (send_queue);
1501 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1502 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1503 "cannot create a send queue for %s\n",
1504 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1505 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1509 /* Check if the operation was a success */
1511 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1513 /* Update the last updated key */
1514 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1515 set_last_updated_idle,
1516 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1517 (GDestroyNotify) g_free);
1521 /* Set the account back to not busy */
1522 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
1523 info->account_name, FALSE);
1525 if (info->callback) {
1526 UpdateAccountInfo *idle_info;
1528 /* This thread is not in the main lock */
1529 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1530 idle_info->mail_op = g_object_ref (info->mail_op);
1531 idle_info->new_headers = (new_headers) ? g_object_ref (new_headers) : NULL;
1532 idle_info->callback = info->callback;
1533 idle_info->user_data = info->user_data;
1534 g_idle_add (idle_update_account_cb, idle_info);
1537 /* Notify about operation end. Note that the info could be
1538 freed before this idle happens, but the mail operation will
1540 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1544 g_object_unref (new_headers);
1546 g_object_unref (all_folders);
1547 g_object_unref (info->account);
1548 if (info->transport_account)
1549 g_object_unref (info->transport_account);
1550 g_free (info->account_name);
1551 g_free (info->retrieve_type);
1552 g_slice_free (UpdateAccountInfo, info);
1560 modest_mail_operation_update_account (ModestMailOperation *self,
1561 const gchar *account_name,
1562 UpdateAccountCallback callback,
1565 GThread *thread = NULL;
1566 UpdateAccountInfo *info = NULL;
1567 ModestMailOperationPrivate *priv = NULL;
1568 ModestAccountMgr *mgr = NULL;
1569 TnyStoreAccount *store_account = NULL;
1570 TnyTransportAccount *transport_account = NULL;
1572 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1573 g_return_val_if_fail (account_name, FALSE);
1575 /* Init mail operation. Set total and done to 0, and do not
1576 update them, this way the progress objects will know that
1577 we have no clue about the number of the objects */
1578 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1581 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1582 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1584 /* Get the store account */
1585 store_account = (TnyStoreAccount *)
1586 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1588 TNY_ACCOUNT_TYPE_STORE);
1590 if (!store_account) {
1591 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1592 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1593 "cannot get tny store account for %s\n", account_name);
1597 priv->account = g_object_ref (store_account);
1599 /* Get the transport account, we can not do it in the thread
1600 due to some problems with dbus */
1601 transport_account = (TnyTransportAccount *)
1602 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1604 if (!transport_account) {
1605 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1606 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1607 "cannot get tny transport account for %s\n", account_name);
1611 /* Create the helper object */
1612 info = g_slice_new (UpdateAccountInfo);
1613 info->mail_op = self;
1614 info->account = store_account;
1615 info->transport_account = transport_account;
1616 info->callback = callback;
1617 info->account_name = g_strdup (account_name);
1618 info->user_data = user_data;
1620 /* Get the message size limit */
1621 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1622 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1623 if (info->max_size == 0)
1624 info->max_size = G_MAXINT;
1626 info->max_size = info->max_size * KB;
1628 /* Get per-account retrieval type */
1629 mgr = modest_runtime_get_account_mgr ();
1630 info->retrieve_type = modest_account_mgr_get_retrieve_type (mgr, account_name);
1632 /* Get per-account message amount retrieval limit */
1633 info->retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, account_name);
1634 if (info->retrieve_limit == 0)
1635 info->retrieve_limit = G_MAXINT;
1637 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1639 /* Set account busy */
1640 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1642 modest_mail_operation_notify_start (self);
1643 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1649 g_object_unref (store_account);
1650 if (transport_account)
1651 g_object_unref (transport_account);
1652 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1654 callback (self, NULL, user_data);
1656 modest_mail_operation_notify_end (self);
1660 /* ******************************************************************* */
1661 /* ************************** STORE ACTIONS ************************* */
1662 /* ******************************************************************* */
1666 modest_mail_operation_create_folder (ModestMailOperation *self,
1667 TnyFolderStore *parent,
1670 ModestMailOperationPrivate *priv;
1671 TnyFolder *new_folder = NULL;
1673 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1674 g_return_val_if_fail (name, NULL);
1676 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1677 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1678 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1679 g_object_ref (parent) :
1680 modest_tny_folder_get_account (TNY_FOLDER (parent));
1682 /* Check for already existing folder */
1683 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1684 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1685 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1686 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1687 _CS("ckdg_ib_folder_already_exists"));
1691 if (TNY_IS_FOLDER (parent)) {
1692 /* Check folder rules */
1693 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1694 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1695 /* Set status failed and set an error */
1696 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1697 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1698 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1699 _("mail_in_ui_folder_create_error"));
1703 if (!strcmp (name, " ") || strchr (name, '/')) {
1704 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1705 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1706 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1707 _("mail_in_ui_folder_create_error"));
1711 /* Create the folder */
1712 modest_mail_operation_notify_start (self);
1713 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1714 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1716 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1719 /* Notify about operation end */
1720 modest_mail_operation_notify_end (self);
1726 modest_mail_operation_remove_folder (ModestMailOperation *self,
1728 gboolean remove_to_trash)
1730 TnyAccount *account;
1731 ModestMailOperationPrivate *priv;
1732 ModestTnyFolderRules rules;
1734 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1735 g_return_if_fail (TNY_IS_FOLDER (folder));
1737 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1739 /* Check folder rules */
1740 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1741 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1742 /* Set status failed and set an error */
1743 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1744 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1745 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1746 _("mail_in_ui_folder_delete_error"));
1750 /* Get the account */
1751 account = modest_tny_folder_get_account (folder);
1752 priv->account = g_object_ref(account);
1753 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1755 /* Delete folder or move to trash */
1756 if (remove_to_trash) {
1757 TnyFolder *trash_folder = NULL;
1758 trash_folder = modest_tny_account_get_special_folder (account,
1759 TNY_FOLDER_TYPE_TRASH);
1760 /* TODO: error_handling */
1762 modest_mail_operation_notify_start (self);
1763 modest_mail_operation_xfer_folder (self, folder,
1764 TNY_FOLDER_STORE (trash_folder),
1766 g_object_unref (trash_folder);
1769 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1771 modest_mail_operation_notify_start (self);
1772 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1773 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1776 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1779 g_object_unref (G_OBJECT (parent));
1781 g_object_unref (G_OBJECT (account));
1784 /* Notify about operation end */
1785 modest_mail_operation_notify_end (self);
1789 transfer_folder_status_cb (GObject *obj,
1793 ModestMailOperation *self;
1794 ModestMailOperationPrivate *priv;
1795 ModestMailOperationState *state;
1796 XFerMsgAsyncHelper *helper;
1798 g_return_if_fail (status != NULL);
1799 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1801 helper = (XFerMsgAsyncHelper *) user_data;
1802 g_return_if_fail (helper != NULL);
1804 self = helper->mail_op;
1805 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1807 priv->done = status->position;
1808 priv->total = status->of_total;
1810 state = modest_mail_operation_clone_state (self);
1812 /* This is not a GDK lock because we are a Tinymail callback
1813 * which is already GDK locked by Tinymail */
1815 /* no gdk_threads_enter (), CHECKED */
1817 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1819 /* no gdk_threads_leave (), CHECKED */
1821 g_slice_free (ModestMailOperationState, state);
1826 transfer_folder_cb (TnyFolder *folder,
1828 TnyFolderStore *into,
1829 TnyFolder *new_folder,
1833 XFerMsgAsyncHelper *helper;
1834 ModestMailOperation *self = NULL;
1835 ModestMailOperationPrivate *priv = NULL;
1837 helper = (XFerMsgAsyncHelper *) user_data;
1838 g_return_if_fail (helper != NULL);
1840 self = helper->mail_op;
1841 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1844 priv->error = g_error_copy (err);
1846 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1847 } else if (cancelled) {
1848 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1849 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1850 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1851 _("Transference of %s was cancelled."),
1852 tny_folder_get_name (folder));
1855 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1858 /* Notify about operation end */
1859 modest_mail_operation_notify_end (self);
1861 /* If user defined callback function was defined, call it */
1862 if (helper->user_callback) {
1864 /* This is not a GDK lock because we are a Tinymail callback
1865 * which is already GDK locked by Tinymail */
1867 /* no gdk_threads_enter (), CHECKED */
1868 helper->user_callback (self, helper->user_data);
1869 /* no gdk_threads_leave () , CHECKED */
1873 g_object_unref (helper->mail_op);
1874 g_slice_free (XFerMsgAsyncHelper, helper);
1879 * This function checks if the new name is a valid name for our local
1880 * folders account. The new name could not be the same than then name
1881 * of any of the mandatory local folders
1883 * We can not rely on tinymail because tinymail does not check the
1884 * name of the virtual folders that the account could have in the case
1885 * that we're doing a rename (because it directly calls Camel which
1886 * knows nothing about our virtual folders).
1888 * In the case of an actual copy/move (i.e. move/copy a folder between
1889 * accounts) tinymail uses the tny_folder_store_create_account which
1890 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1891 * checks the new name of the folder, so this call in that case
1892 * wouldn't be needed. *But* NOTE that if tinymail changes its
1893 * implementation (if folder transfers within the same account is no
1894 * longer implemented as a rename) this call will allow Modest to work
1897 * If the new name is not valid, this function will set the status to
1898 * failed and will set also an error in the mail operation
1901 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1902 TnyFolderStore *into,
1903 const gchar *new_name)
1905 if (TNY_IS_ACCOUNT (into) &&
1906 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1907 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1909 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1910 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1911 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1912 _CS("ckdg_ib_folder_already_exists"));
1919 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1921 TnyFolderStore *parent,
1922 gboolean delete_original,
1923 XferAsyncUserCallback user_callback,
1926 ModestMailOperationPrivate *priv = NULL;
1927 ModestTnyFolderRules parent_rules = 0, rules;
1928 XFerMsgAsyncHelper *helper = NULL;
1929 const gchar *folder_name = NULL;
1930 const gchar *error_msg;
1932 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1933 g_return_if_fail (TNY_IS_FOLDER (folder));
1934 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1936 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1937 folder_name = tny_folder_get_name (folder);
1939 /* Set the error msg */
1940 error_msg = _("mail_in_ui_folder_move_target_error");
1942 /* Get account and set it into mail_operation */
1943 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1944 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1945 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1947 /* Get folder rules */
1948 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1949 if (TNY_IS_FOLDER (parent))
1950 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1952 /* Apply operation constraints */
1953 if ((gpointer) parent == (gpointer) folder ||
1954 (!TNY_IS_FOLDER_STORE (parent)) ||
1955 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1958 } else if (TNY_IS_FOLDER (parent) &&
1959 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1963 } else if (TNY_IS_FOLDER (parent) &&
1964 TNY_IS_FOLDER_STORE (folder) &&
1965 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1966 TNY_FOLDER_STORE (folder))) {
1967 /* Do not move a parent into a child */
1969 } else if (TNY_IS_FOLDER_STORE (parent) &&
1970 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
1971 /* Check that the new folder name is not used by any
1974 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1975 /* Check that the new folder name is not used by any
1976 special local folder */
1979 /* Create the helper */
1980 helper = g_slice_new0 (XFerMsgAsyncHelper);
1981 helper->mail_op = g_object_ref (self);
1982 helper->dest_folder = NULL;
1983 helper->headers = NULL;
1984 helper->user_callback = user_callback;
1985 helper->user_data = user_data;
1987 /* Move/Copy folder */
1988 modest_mail_operation_notify_start (self);
1989 tny_folder_copy_async (folder,
1991 tny_folder_get_name (folder),
1994 transfer_folder_status_cb,
2000 /* Set status failed and set an error */
2001 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2002 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2003 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2006 /* Call the user callback if exists */
2008 user_callback (self, user_data);
2010 /* Notify the queue */
2011 modest_mail_operation_notify_end (self);
2015 modest_mail_operation_rename_folder (ModestMailOperation *self,
2019 ModestMailOperationPrivate *priv;
2020 ModestTnyFolderRules rules;
2021 XFerMsgAsyncHelper *helper;
2023 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2024 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2025 g_return_if_fail (name);
2027 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2029 /* Get account and set it into mail_operation */
2030 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2031 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2033 /* Check folder rules */
2034 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2035 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2036 /* Set status failed and set an error */
2037 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2038 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2039 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2040 _("FIXME: unable to rename"));
2042 /* Notify about operation end */
2043 modest_mail_operation_notify_end (self);
2044 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2045 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2046 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2047 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2048 _("FIXME: unable to rename"));
2049 /* Notify about operation end */
2050 modest_mail_operation_notify_end (self);
2052 TnyFolderStore *into;
2054 into = tny_folder_get_folder_store (folder);
2056 /* Check that the new folder name is not used by any
2057 special local folder */
2058 if (new_name_valid_if_local_account (priv, into, name)) {
2059 /* Create the helper */
2060 helper = g_slice_new0 (XFerMsgAsyncHelper);
2061 helper->mail_op = g_object_ref(self);
2062 helper->dest_folder = NULL;
2063 helper->headers = NULL;
2064 helper->user_callback = NULL;
2065 helper->user_data = NULL;
2067 /* Rename. Camel handles folder subscription/unsubscription */
2068 modest_mail_operation_notify_start (self);
2069 tny_folder_copy_async (folder, into, name, TRUE,
2071 transfer_folder_status_cb,
2074 modest_mail_operation_notify_end (self);
2076 g_object_unref (into);
2080 /* ******************************************************************* */
2081 /* ************************** MSG ACTIONS ************************* */
2082 /* ******************************************************************* */
2085 modest_mail_operation_get_msg (ModestMailOperation *self,
2087 GetMsgAsyncUserCallback user_callback,
2090 GetMsgInfo *helper = NULL;
2092 ModestMailOperationPrivate *priv;
2094 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2095 g_return_if_fail (TNY_IS_HEADER (header));
2097 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2098 folder = tny_header_get_folder (header);
2100 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2101 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2105 /* Get account and set it into mail_operation */
2106 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2108 /* Check for cached messages */
2109 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2110 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2112 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2114 /* Create the helper */
2115 helper = g_slice_new0 (GetMsgInfo);
2116 helper->header = g_object_ref (header);
2117 helper->mail_op = g_object_ref (self);
2118 helper->user_callback = user_callback;
2119 helper->user_data = user_data;
2120 helper->destroy_notify = NULL;
2121 helper->last_total_bytes = 0;
2122 helper->sum_total_bytes = 0;
2123 helper->total_bytes = tny_header_get_message_size (header);
2125 modest_mail_operation_notify_start (self);
2126 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2128 g_object_unref (G_OBJECT (folder));
2132 get_msg_status_cb (GObject *obj,
2136 GetMsgInfo *helper = NULL;
2138 g_return_if_fail (status != NULL);
2139 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2141 helper = (GetMsgInfo *) user_data;
2142 g_return_if_fail (helper != NULL);
2144 /* Notify progress */
2145 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2146 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2150 get_msg_async_cb (TnyFolder *folder,
2156 GetMsgInfo *info = NULL;
2157 ModestMailOperationPrivate *priv = NULL;
2160 info = (GetMsgInfo *) user_data;
2162 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2164 finished = (priv->done == priv->total) ? TRUE : FALSE;
2167 if (canceled || err) {
2168 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2170 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2171 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2174 /* Set the success status before calling the user callback */
2175 if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2176 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2180 /* Call the user callback */
2181 if (info->user_callback)
2182 info->user_callback (info->mail_op, info->header, canceled,
2183 msg, err, info->user_data);
2185 /* Notify about operation end if this is the last callback */
2187 /* Free user data */
2188 if (info->destroy_notify)
2189 info->destroy_notify (info->user_data);
2191 /* Notify about operation end */
2192 modest_mail_operation_notify_end (info->mail_op);
2196 g_object_unref (info->header);
2197 g_object_unref (info->mail_op);
2198 g_slice_free (GetMsgInfo, info);
2202 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2203 TnyList *header_list,
2204 GetMsgAsyncUserCallback user_callback,
2206 GDestroyNotify notify)
2208 ModestMailOperationPrivate *priv = NULL;
2209 gboolean size_ok = TRUE;
2211 TnyIterator *iter = NULL;
2213 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2215 /* Init mail operation */
2216 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2217 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2218 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2220 priv->total = tny_list_get_length(header_list);
2222 /* Get account and set it into mail_operation */
2223 if (tny_list_get_length (header_list) >= 1) {
2224 iter = tny_list_create_iterator (header_list);
2225 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2227 TnyFolder *folder = tny_header_get_folder (header);
2229 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2230 g_object_unref (folder);
2232 g_object_unref (header);
2235 if (tny_list_get_length (header_list) == 1) {
2236 g_object_unref (iter);
2241 /* Get msg size limit */
2242 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2243 MODEST_CONF_MSG_SIZE_LIMIT,
2246 g_clear_error (&(priv->error));
2247 max_size = G_MAXINT;
2249 max_size = max_size * KB;
2252 /* Check message size limits. If there is only one message
2253 always retrieve it */
2255 while (!tny_iterator_is_done (iter) && size_ok) {
2256 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2258 if (tny_header_get_message_size (header) >= max_size)
2260 g_object_unref (header);
2263 tny_iterator_next (iter);
2265 g_object_unref (iter);
2269 modest_mail_operation_notify_start (self);
2271 iter = tny_list_create_iterator (header_list);
2272 while (!tny_iterator_is_done (iter)) {
2273 GetMsgInfo *msg_info = NULL;
2274 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2275 TnyFolder *folder = tny_header_get_folder (header);
2277 /* Create the message info */
2278 msg_info = g_slice_new0 (GetMsgInfo);
2279 msg_info->mail_op = g_object_ref (self);
2280 msg_info->header = g_object_ref (header);
2281 msg_info->user_callback = user_callback;
2282 msg_info->user_data = user_data;
2283 msg_info->destroy_notify = notify;
2284 msg_info->last_total_bytes = 0;
2285 msg_info->sum_total_bytes = 0;
2286 msg_info->total_bytes = compute_message_list_size (header_list);
2288 /* The callback will call it per each header */
2289 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2291 /* Free and go on */
2292 g_object_unref (header);
2293 g_object_unref (folder);
2294 tny_iterator_next (iter);
2296 g_object_unref (iter);
2298 /* Set status failed and set an error */
2299 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2300 /* FIXME: the error msg is different for pop */
2301 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2302 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2303 _("emev_ni_ui_imap_msg_size_exceed_error"));
2304 /* Remove from queue and free resources */
2305 modest_mail_operation_notify_end (self);
2313 modest_mail_operation_remove_msg (ModestMailOperation *self,
2315 gboolean remove_to_trash /*ignored*/)
2318 ModestMailOperationPrivate *priv;
2320 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2321 g_return_if_fail (TNY_IS_HEADER (header));
2323 if (remove_to_trash)
2324 g_warning ("remove to trash is not implemented");
2326 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2327 folder = tny_header_get_folder (header);
2329 /* Get account and set it into mail_operation */
2330 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2331 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2332 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2334 /* remove message from folder */
2335 tny_folder_remove_msg (folder, header, &(priv->error));
2337 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2338 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2340 modest_mail_operation_notify_start (self);
2342 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2343 TNY_IS_CAMEL_POP_FOLDER (folder))
2344 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> dont expunge */
2346 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2352 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2354 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2357 g_object_unref (G_OBJECT (folder));
2359 /* Notify about operation end */
2360 modest_mail_operation_notify_end (self);
2364 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2366 gboolean remove_to_trash /*ignored*/)
2369 ModestMailOperationPrivate *priv;
2370 TnyIterator *iter = NULL;
2371 TnyHeader *header = NULL;
2372 TnyList *remove_headers = NULL;
2373 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2375 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2376 g_return_if_fail (TNY_IS_LIST (headers));
2378 if (remove_to_trash)
2379 g_warning ("remove to trash is not implemented");
2381 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2383 remove_headers = g_object_ref(headers);
2385 /* Get folder from first header and sync it */
2386 iter = tny_list_create_iterator (headers);
2387 header = TNY_HEADER (tny_iterator_get_current (iter));
2388 folder = tny_header_get_folder (header);
2390 /* Don't remove messages that are being sent */
2391 if (modest_tny_folder_is_local_folder (folder)) {
2392 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2394 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2395 TnyTransportAccount *traccount = NULL;
2396 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2397 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2399 ModestTnySendQueueStatus status;
2400 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2401 TnyIterator *iter = tny_list_create_iterator(headers);
2402 g_object_unref(remove_headers);
2403 remove_headers = TNY_LIST(tny_simple_list_new());
2404 while (!tny_iterator_is_done(iter)) {
2406 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2407 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2408 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2409 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2410 tny_list_append(remove_headers, G_OBJECT(hdr));
2412 g_object_unref(hdr);
2414 tny_iterator_next(iter);
2416 g_object_unref(iter);
2417 g_object_unref(traccount);
2421 /* Get account and set it into mail_operation */
2422 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2423 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2424 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2426 /* remove message from folder */
2427 modest_mail_operation_notify_start (self);
2429 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2431 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2432 TNY_IS_CAMEL_POP_FOLDER (folder))
2433 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> don't expunge */
2436 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2442 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2444 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2447 g_object_unref (remove_headers);
2448 g_object_unref (header);
2449 g_object_unref (iter);
2450 g_object_unref (G_OBJECT (folder));
2452 /* Notify about operation end */
2453 modest_mail_operation_notify_end (self);
2457 notify_progress_of_multiple_messages (ModestMailOperation *self,
2459 gint *last_total_bytes,
2460 gint *sum_total_bytes,
2462 gboolean increment_done)
2464 ModestMailOperationPrivate *priv;
2465 ModestMailOperationState *state;
2466 gboolean is_num_bytes;
2468 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2470 /* We know that tinymail sends us information about
2471 transferred bytes with this particular message */
2472 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2474 state = modest_mail_operation_clone_state (self);
2475 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2476 /* We know that we're in a different message when the
2477 total number of bytes to transfer is different. Of
2478 course it could fail if we're transferring messages
2479 of the same size, but this is a workarround */
2480 if (status->of_total != *last_total_bytes) {
2481 /* We need to increment the done when there is
2482 no information about each individual
2483 message, we need to do this in message
2484 transfers, and we don't do it for getting
2488 *sum_total_bytes += *last_total_bytes;
2489 *last_total_bytes = status->of_total;
2491 state->bytes_done += status->position + *sum_total_bytes;
2492 state->bytes_total = total_bytes;
2494 /* Notify the status change. Only notify about changes
2495 referred to bytes */
2496 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2500 g_slice_free (ModestMailOperationState, state);
2504 transfer_msgs_status_cb (GObject *obj,
2508 XFerMsgAsyncHelper *helper;
2510 g_return_if_fail (status != NULL);
2511 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2513 helper = (XFerMsgAsyncHelper *) user_data;
2514 g_return_if_fail (helper != NULL);
2516 /* Notify progress */
2517 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2518 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2523 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2525 XFerMsgAsyncHelper *helper;
2526 ModestMailOperation *self;
2527 ModestMailOperationPrivate *priv;
2528 TnyIterator *iter = NULL;
2529 TnyHeader *header = NULL;
2531 helper = (XFerMsgAsyncHelper *) user_data;
2532 self = helper->mail_op;
2534 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2537 priv->error = g_error_copy (err);
2539 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2540 } else if (cancelled) {
2541 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2542 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2543 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2544 _("Error trying to refresh the contents of %s"),
2545 tny_folder_get_name (folder));
2548 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2550 /* Update folder counts */
2551 tny_folder_poke_status (folder);
2552 tny_folder_poke_status (helper->dest_folder);
2556 /* Mark headers as deleted and seen */
2557 if ((helper->delete) &&
2558 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2559 iter = tny_list_create_iterator (helper->headers);
2560 while (!tny_iterator_is_done (iter)) {
2561 header = TNY_HEADER (tny_iterator_get_current (iter));
2562 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2563 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2564 g_object_unref (header);
2566 tny_iterator_next (iter);
2572 /* Notify about operation end */
2573 modest_mail_operation_notify_end (self);
2575 /* If user defined callback function was defined, call it */
2576 if (helper->user_callback) {
2577 /* This is not a GDK lock because we are a Tinymail callback and
2578 * Tinymail already acquires the Gdk lock */
2580 /* no gdk_threads_enter (), CHECKED */
2581 helper->user_callback (self, helper->user_data);
2582 /* no gdk_threads_leave (), CHECKED */
2586 if (helper->headers)
2587 g_object_unref (helper->headers);
2588 if (helper->dest_folder)
2589 g_object_unref (helper->dest_folder);
2590 if (helper->mail_op)
2591 g_object_unref (helper->mail_op);
2593 g_object_unref (folder);
2595 g_object_unref (iter);
2596 g_slice_free (XFerMsgAsyncHelper, helper);
2600 compute_message_list_size (TnyList *headers)
2605 iter = tny_list_create_iterator (headers);
2606 while (!tny_iterator_is_done (iter)) {
2607 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2608 size += tny_header_get_message_size (header);
2609 g_object_unref (header);
2610 tny_iterator_next (iter);
2612 g_object_unref (iter);
2618 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2621 gboolean delete_original,
2622 XferAsyncUserCallback user_callback,
2625 ModestMailOperationPrivate *priv = NULL;
2626 TnyIterator *iter = NULL;
2627 TnyFolder *src_folder = NULL;
2628 XFerMsgAsyncHelper *helper = NULL;
2629 TnyHeader *header = NULL;
2630 ModestTnyFolderRules rules = 0;
2632 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2633 g_return_if_fail (headers && TNY_IS_LIST (headers));
2634 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2636 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2637 priv->total = tny_list_get_length (headers);
2639 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2640 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2642 /* Apply folder rules */
2643 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2644 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2645 /* Set status failed and set an error */
2646 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2647 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2648 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2649 _CS("ckct_ib_unable_to_paste_here"));
2650 /* Notify the queue */
2651 modest_mail_operation_notify_end (self);
2655 /* Get source folder */
2656 iter = tny_list_create_iterator (headers);
2657 header = TNY_HEADER (tny_iterator_get_current (iter));
2659 src_folder = tny_header_get_folder (header);
2660 g_object_unref (header);
2662 g_object_unref (iter);
2664 if (src_folder == NULL) {
2665 /* Notify the queue */
2666 modest_mail_operation_notify_end (self);
2668 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2673 /* Check folder source and destination */
2674 if (src_folder == folder) {
2675 /* Set status failed and set an error */
2676 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2677 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2678 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2679 _("mcen_ib_unable_to_copy_samefolder"));
2681 /* Notify the queue */
2682 modest_mail_operation_notify_end (self);
2685 g_object_unref (src_folder);
2689 /* Create the helper */
2690 helper = g_slice_new0 (XFerMsgAsyncHelper);
2691 helper->mail_op = g_object_ref(self);
2692 helper->dest_folder = g_object_ref(folder);
2693 helper->headers = g_object_ref(headers);
2694 helper->user_callback = user_callback;
2695 helper->user_data = user_data;
2696 helper->delete = delete_original;
2697 helper->last_total_bytes = 0;
2698 helper->sum_total_bytes = 0;
2699 helper->total_bytes = compute_message_list_size (headers);
2701 /* Get account and set it into mail_operation */
2702 priv->account = modest_tny_folder_get_account (src_folder);
2704 /* Transfer messages */
2705 modest_mail_operation_notify_start (self);
2706 tny_folder_transfer_msgs_async (src_folder,
2711 transfer_msgs_status_cb,
2717 on_refresh_folder (TnyFolder *folder,
2722 RefreshAsyncHelper *helper = NULL;
2723 ModestMailOperation *self = NULL;
2724 ModestMailOperationPrivate *priv = NULL;
2726 helper = (RefreshAsyncHelper *) user_data;
2727 self = helper->mail_op;
2728 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2730 g_return_if_fail(priv!=NULL);
2733 priv->error = g_error_copy (error);
2734 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2739 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2740 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2741 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2742 _("Error trying to refresh the contents of %s"),
2743 tny_folder_get_name (folder));
2747 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2750 /* Call user defined callback, if it exists */
2751 if (helper->user_callback) {
2753 /* This is not a GDK lock because we are a Tinymail callback and
2754 * Tinymail already acquires the Gdk lock */
2755 helper->user_callback (self, folder, helper->user_data);
2759 g_slice_free (RefreshAsyncHelper, helper);
2761 /* Notify about operation end */
2762 modest_mail_operation_notify_end (self);
2763 g_object_unref(self);
2767 on_refresh_folder_status_update (GObject *obj,
2771 RefreshAsyncHelper *helper = NULL;
2772 ModestMailOperation *self = NULL;
2773 ModestMailOperationPrivate *priv = NULL;
2774 ModestMailOperationState *state;
2776 g_return_if_fail (user_data != NULL);
2777 g_return_if_fail (status != NULL);
2778 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2780 helper = (RefreshAsyncHelper *) user_data;
2781 self = helper->mail_op;
2782 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2784 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2786 priv->done = status->position;
2787 priv->total = status->of_total;
2789 state = modest_mail_operation_clone_state (self);
2791 /* This is not a GDK lock because we are a Tinymail callback and
2792 * Tinymail already acquires the Gdk lock */
2793 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2795 g_slice_free (ModestMailOperationState, state);
2799 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2801 RefreshAsyncUserCallback user_callback,
2804 ModestMailOperationPrivate *priv = NULL;
2805 RefreshAsyncHelper *helper = NULL;
2807 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2809 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2811 /* Get account and set it into mail_operation */
2812 priv->account = modest_tny_folder_get_account (folder);
2813 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2815 /* Create the helper */
2816 helper = g_slice_new0 (RefreshAsyncHelper);
2817 helper->mail_op = g_object_ref(self);
2818 helper->user_callback = user_callback;
2819 helper->user_data = user_data;
2821 /* Refresh the folder. TODO: tinymail could issue a status
2822 updates before the callback call then this could happen. We
2823 must review the design */
2824 modest_mail_operation_notify_start (self);
2825 tny_folder_refresh_async (folder,
2827 on_refresh_folder_status_update,
2833 modest_mail_operation_notify_start (ModestMailOperation *self)
2835 ModestMailOperationPrivate *priv = NULL;
2837 g_return_if_fail (self);
2839 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2841 /* Ensure that all the fields are filled correctly */
2842 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
2844 /* Notify the observers about the mail operation. We do not
2845 wrapp this emission because we assume that this function is
2846 always called from within the main lock */
2847 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
2852 * It's used by the mail operation queue to notify the observers
2853 * attached to that signal that the operation finished. We need to use
2854 * that because tinymail does not give us the progress of a given
2855 * operation when it finishes (it directly calls the operation
2859 modest_mail_operation_notify_end (ModestMailOperation *self)
2861 ModestMailOperationPrivate *priv = NULL;
2863 g_return_if_fail (self);
2865 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2867 /* Notify the observers about the mail operation end. We do
2868 not wrapp this emission because we assume that this
2869 function is always called from within the main lock */
2870 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
2872 /* Remove the error user data */
2873 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
2874 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
2878 modest_mail_operation_get_account (ModestMailOperation *self)
2880 ModestMailOperationPrivate *priv = NULL;
2882 g_return_val_if_fail (self, NULL);
2884 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2886 return (priv->account) ? g_object_ref (priv->account) : NULL;
2890 modest_mail_operation_noop (ModestMailOperation *self)
2892 ModestMailOperationPrivate *priv = NULL;
2894 g_return_if_fail (self);
2896 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2897 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2898 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2902 /* This mail operation does nothing actually */
2903 modest_mail_operation_notify_start (self);
2904 modest_mail_operation_notify_end (self);