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 static guint compute_message_array_size (GPtrArray *headers);
98 static int compare_headers_by_date (gconstpointer a,
101 enum _ModestMailOperationSignals
103 PROGRESS_CHANGED_SIGNAL,
104 OPERATION_STARTED_SIGNAL,
105 OPERATION_FINISHED_SIGNAL,
109 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
110 struct _ModestMailOperationPrivate {
116 ErrorCheckingUserCallback error_checking;
117 gpointer error_checking_user_data;
118 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
119 ModestMailOperationStatus status;
120 ModestMailOperationTypeOperation op_type;
123 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
124 MODEST_TYPE_MAIL_OPERATION, \
125 ModestMailOperationPrivate))
127 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
128 priv->status = new_status;\
133 GetMsgAsyncUserCallback user_callback;
136 ModestMailOperation *mail_op;
137 GDestroyNotify destroy_notify;
138 gint last_total_bytes;
139 gint sum_total_bytes;
144 ModestMailOperation *mail_op;
146 gulong msg_sent_handler;
147 gulong error_happened_handler;
150 static void send_mail_msg_sent_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
151 guint nth, guint total, gpointer userdata);
152 static void send_mail_error_happened_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
153 GError *error, gpointer userdata);
154 static void common_send_mail_operation_end (TnySendQueue *queue, TnyMsg *msg,
157 typedef struct _RefreshAsyncHelper {
158 ModestMailOperation *mail_op;
159 RefreshAsyncUserCallback user_callback;
161 } RefreshAsyncHelper;
163 typedef struct _XFerMsgAsyncHelper
165 ModestMailOperation *mail_op;
167 TnyFolder *dest_folder;
168 XferAsyncUserCallback user_callback;
171 gint last_total_bytes;
172 gint sum_total_bytes;
174 } XFerMsgAsyncHelper;
176 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
180 static void modest_mail_operation_create_msg (ModestMailOperation *self,
181 const gchar *from, const gchar *to,
182 const gchar *cc, const gchar *bcc,
183 const gchar *subject, const gchar *plain_body,
184 const gchar *html_body, const GList *attachments_list,
185 const GList *images_list,
186 TnyHeaderFlags priority_flags,
187 ModestMailOperationCreateMsgCallback callback,
190 static gboolean idle_notify_queue (gpointer data);
193 ModestMailOperation *mail_op;
201 GList *attachments_list;
203 TnyHeaderFlags priority_flags;
204 ModestMailOperationCreateMsgCallback callback;
210 ModestMailOperation *mail_op;
212 ModestMailOperationCreateMsgCallback callback;
217 static GObjectClass *parent_class = NULL;
219 static guint signals[NUM_SIGNALS] = {0};
222 modest_mail_operation_get_type (void)
224 static GType my_type = 0;
226 static const GTypeInfo my_info = {
227 sizeof(ModestMailOperationClass),
228 NULL, /* base init */
229 NULL, /* base finalize */
230 (GClassInitFunc) modest_mail_operation_class_init,
231 NULL, /* class finalize */
232 NULL, /* class data */
233 sizeof(ModestMailOperation),
235 (GInstanceInitFunc) modest_mail_operation_init,
238 my_type = g_type_register_static (G_TYPE_OBJECT,
239 "ModestMailOperation",
246 modest_mail_operation_class_init (ModestMailOperationClass *klass)
248 GObjectClass *gobject_class;
249 gobject_class = (GObjectClass*) klass;
251 parent_class = g_type_class_peek_parent (klass);
252 gobject_class->finalize = modest_mail_operation_finalize;
254 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
257 * ModestMailOperation::progress-changed
258 * @self: the #MailOperation that emits the signal
259 * @user_data: user data set when the signal handler was connected
261 * Emitted when the progress of a mail operation changes
263 signals[PROGRESS_CHANGED_SIGNAL] =
264 g_signal_new ("progress-changed",
265 G_TYPE_FROM_CLASS (gobject_class),
267 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
269 g_cclosure_marshal_VOID__POINTER,
270 G_TYPE_NONE, 1, G_TYPE_POINTER);
274 * This signal is issued whenever a mail operation starts, and
275 * starts mean when the tinymail operation is issued. This
276 * means that it could happen that something wrong happens and
277 * the tinymail function is never called. In this situation a
278 * operation-finished will be issued without any
281 signals[OPERATION_STARTED_SIGNAL] =
282 g_signal_new ("operation-started",
283 G_TYPE_FROM_CLASS (gobject_class),
285 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
287 g_cclosure_marshal_VOID__VOID,
292 * This signal is issued whenever a mail operation
293 * finishes. Note that this signal could be issued without any
294 * previous "operation-started" signal, because this last one
295 * is only issued when the tinymail operation is successfully
298 signals[OPERATION_FINISHED_SIGNAL] =
299 g_signal_new ("operation-finished",
300 G_TYPE_FROM_CLASS (gobject_class),
302 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
304 g_cclosure_marshal_VOID__VOID,
309 modest_mail_operation_init (ModestMailOperation *obj)
311 ModestMailOperationPrivate *priv;
313 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
315 priv->account = NULL;
316 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
317 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
322 priv->error_checking = NULL;
323 priv->error_checking_user_data = NULL;
327 modest_mail_operation_finalize (GObject *obj)
329 ModestMailOperationPrivate *priv;
331 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
336 g_error_free (priv->error);
340 g_object_unref (priv->source);
344 g_object_unref (priv->account);
345 priv->account = NULL;
349 G_OBJECT_CLASS(parent_class)->finalize (obj);
353 modest_mail_operation_new (GObject *source)
355 ModestMailOperation *obj;
356 ModestMailOperationPrivate *priv;
358 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
359 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
362 priv->source = g_object_ref(source);
368 modest_mail_operation_new_with_error_handling (GObject *source,
369 ErrorCheckingUserCallback error_handler,
371 ErrorCheckingUserDataDestroyer error_handler_destroyer)
373 ModestMailOperation *obj;
374 ModestMailOperationPrivate *priv;
376 obj = modest_mail_operation_new (source);
377 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
379 g_return_val_if_fail (error_handler != NULL, obj);
380 priv->error_checking = error_handler;
381 priv->error_checking_user_data = user_data;
382 priv->error_checking_user_data_destroyer = error_handler_destroyer;
388 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
390 ModestMailOperationPrivate *priv;
392 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
393 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
395 /* Call the user callback */
396 if (priv->error_checking != NULL)
397 priv->error_checking (self, priv->error_checking_user_data);
401 ModestMailOperationTypeOperation
402 modest_mail_operation_get_type_operation (ModestMailOperation *self)
404 ModestMailOperationPrivate *priv;
406 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
408 return priv->op_type;
412 modest_mail_operation_is_mine (ModestMailOperation *self,
415 ModestMailOperationPrivate *priv;
417 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
418 if (priv->source == NULL) return FALSE;
420 return priv->source == me;
424 modest_mail_operation_get_source (ModestMailOperation *self)
426 ModestMailOperationPrivate *priv;
428 g_return_val_if_fail (self, NULL);
430 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
432 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
436 return (priv->source) ? g_object_ref (priv->source) : NULL;
439 ModestMailOperationStatus
440 modest_mail_operation_get_status (ModestMailOperation *self)
442 ModestMailOperationPrivate *priv;
444 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
445 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
446 MODEST_MAIL_OPERATION_STATUS_INVALID);
448 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
450 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
451 return MODEST_MAIL_OPERATION_STATUS_INVALID;
458 modest_mail_operation_get_error (ModestMailOperation *self)
460 ModestMailOperationPrivate *priv;
462 g_return_val_if_fail (self, NULL);
463 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
465 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
468 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
476 modest_mail_operation_cancel (ModestMailOperation *self)
478 ModestMailOperationPrivate *priv;
479 gboolean canceled = FALSE;
481 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
483 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
485 /* Note that if we call cancel with an already canceled mail
486 operation the progress changed signal won't be emitted */
487 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
491 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
493 /* Cancel the mail operation. We need to wrap it between this
494 start/stop operations to allow following calls to the
496 g_return_val_if_fail (priv->account, FALSE);
498 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
499 ModestTnySendQueue *queue;
500 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account));
501 /* Cancel sending without removing the item */
502 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), FALSE, NULL);
504 /* Cancel operation */
505 tny_account_cancel (priv->account);
512 modest_mail_operation_get_task_done (ModestMailOperation *self)
514 ModestMailOperationPrivate *priv;
516 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
518 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
523 modest_mail_operation_get_task_total (ModestMailOperation *self)
525 ModestMailOperationPrivate *priv;
527 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
529 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
534 modest_mail_operation_is_finished (ModestMailOperation *self)
536 ModestMailOperationPrivate *priv;
537 gboolean retval = FALSE;
539 if (!MODEST_IS_MAIL_OPERATION (self)) {
540 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
544 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
546 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
547 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
548 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
549 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
559 * Creates an image of the current state of a mail operation, the
560 * caller must free it
562 static ModestMailOperationState *
563 modest_mail_operation_clone_state (ModestMailOperation *self)
565 ModestMailOperationState *state;
566 ModestMailOperationPrivate *priv;
568 /* FIXME: this should be fixed properly
570 * in some cases, priv was NULL, so checking here to
573 g_return_val_if_fail (self, NULL);
574 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
575 g_return_val_if_fail (priv, NULL);
580 state = g_slice_new (ModestMailOperationState);
582 state->status = priv->status;
583 state->op_type = priv->op_type;
584 state->done = priv->done;
585 state->total = priv->total;
586 state->finished = modest_mail_operation_is_finished (self);
587 state->bytes_done = 0;
588 state->bytes_total = 0;
593 /* ******************************************************************* */
594 /* ************************** SEND ACTIONS ************************* */
595 /* ******************************************************************* */
598 modest_mail_operation_send_mail (ModestMailOperation *self,
599 TnyTransportAccount *transport_account,
602 TnySendQueue *send_queue = NULL;
603 ModestMailOperationPrivate *priv;
606 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
607 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
608 g_return_if_fail (TNY_IS_MSG (msg));
610 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
612 /* Get account and set it into mail_operation */
613 priv->account = g_object_ref (transport_account);
614 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
618 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
619 if (!TNY_IS_SEND_QUEUE(send_queue)) {
620 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
621 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
622 "modest: could not find send queue for account\n");
623 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
624 modest_mail_operation_notify_end (self);
627 /* Add the msg to the queue */
628 modest_mail_operation_notify_start (self);
629 modest_tny_send_queue_add (MODEST_TNY_SEND_QUEUE(send_queue),
633 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
635 info = g_slice_new0 (SendMsgInfo);
637 info->mail_op = g_object_ref (self);
638 info->msg = g_object_ref (msg);
639 info->msg_sent_handler = g_signal_connect (G_OBJECT (send_queue), "msg-sent",
640 G_CALLBACK (send_mail_msg_sent_handler), info);
641 info->error_happened_handler = g_signal_connect (G_OBJECT (send_queue), "error-happened",
642 G_CALLBACK (send_mail_error_happened_handler), info);
648 common_send_mail_operation_end (TnySendQueue *queue, TnyMsg *msg,
651 g_signal_handler_disconnect (queue, info->msg_sent_handler);
652 g_signal_handler_disconnect (queue, info->error_happened_handler);
654 g_object_unref (info->msg);
655 modest_mail_operation_notify_end (info->mail_op);
656 g_object_unref (info->mail_op);
658 g_slice_free (SendMsgInfo, info);
662 send_mail_msg_sent_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
663 guint nth, guint total, gpointer userdata)
665 SendMsgInfo *info = (SendMsgInfo *) userdata;
667 if (!strcmp (tny_msg_get_url_string (msg),
668 tny_msg_get_url_string (info->msg))) {
669 ModestMailOperationPrivate *priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
670 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
672 common_send_mail_operation_end (queue, msg, info);
677 send_mail_error_happened_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
678 GError *error, gpointer userdata)
680 SendMsgInfo *info = (SendMsgInfo *) userdata;
682 if (!strcmp (tny_msg_get_url_string (msg),
683 tny_msg_get_url_string (info->msg))) {
684 ModestMailOperationPrivate *priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
685 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
686 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
687 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
688 "modest: send mail failed\n");
690 common_send_mail_operation_end (queue, msg, info);
696 idle_create_msg_cb (gpointer idle_data)
698 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
700 /* This is a GDK lock because we are an idle callback and
701 * info->callback can contain Gtk+ code */
703 gdk_threads_enter (); /* CHECKED */
704 info->callback (info->mail_op, info->msg, info->userdata);
706 g_object_unref (info->mail_op);
708 g_object_unref (info->msg);
709 g_slice_free (CreateMsgIdleInfo, info);
710 gdk_threads_leave (); /* CHECKED */
716 create_msg_thread (gpointer thread_data)
718 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
719 TnyMsg *new_msg = NULL;
720 ModestMailOperationPrivate *priv;
722 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
723 if (info->html_body == NULL) {
724 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
725 info->bcc, info->subject, info->plain_body,
726 info->attachments_list);
728 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
729 info->bcc, info->subject, info->html_body,
730 info->plain_body, info->attachments_list,
737 /* Set priority flags in message */
738 header = tny_msg_get_header (new_msg);
739 tny_header_set_flag (header, info->priority_flags);
741 /* Set attachment flags in message */
742 if (info->attachments_list != NULL)
743 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
745 g_object_unref (G_OBJECT(header));
747 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
748 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
749 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
750 "modest: failed to create a new msg\n");
758 g_free (info->plain_body);
759 g_free (info->html_body);
760 g_free (info->subject);
761 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
762 g_list_free (info->attachments_list);
763 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
764 g_list_free (info->images_list);
766 if (info->callback) {
767 CreateMsgIdleInfo *idle_info;
768 idle_info = g_slice_new0 (CreateMsgIdleInfo);
769 idle_info->mail_op = g_object_ref (info->mail_op);
770 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
771 idle_info->callback = info->callback;
772 idle_info->userdata = info->userdata;
773 g_idle_add (idle_create_msg_cb, idle_info);
775 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
778 g_object_unref (info->mail_op);
779 g_slice_free (CreateMsgInfo, info);
784 modest_mail_operation_create_msg (ModestMailOperation *self,
785 const gchar *from, const gchar *to,
786 const gchar *cc, const gchar *bcc,
787 const gchar *subject, const gchar *plain_body,
788 const gchar *html_body,
789 const GList *attachments_list,
790 const GList *images_list,
791 TnyHeaderFlags priority_flags,
792 ModestMailOperationCreateMsgCallback callback,
795 CreateMsgInfo *info = NULL;
797 info = g_slice_new0 (CreateMsgInfo);
798 info->mail_op = g_object_ref (self);
800 info->from = g_strdup (from);
801 info->to = g_strdup (to);
802 info->cc = g_strdup (cc);
803 info->bcc = g_strdup (bcc);
804 info->subject = g_strdup (subject);
805 info->plain_body = g_strdup (plain_body);
806 info->html_body = g_strdup (html_body);
807 info->attachments_list = g_list_copy ((GList *) attachments_list);
808 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
809 info->images_list = g_list_copy ((GList *) images_list);
810 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
811 info->priority_flags = priority_flags;
813 info->callback = callback;
814 info->userdata = userdata;
816 g_thread_create (create_msg_thread, info, FALSE, NULL);
821 TnyTransportAccount *transport_account;
826 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
830 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
831 TnyFolder *draft_folder = NULL;
832 TnyFolder *outbox_folder = NULL;
840 /* Call mail operation */
841 modest_mail_operation_send_mail (self, info->transport_account, msg);
843 /* Remove old mail from its source folder */
844 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
845 TNY_FOLDER_TYPE_DRAFTS);
846 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
847 TNY_FOLDER_TYPE_OUTBOX);
848 if (info->draft_msg != NULL) {
849 TnyFolder *folder = NULL;
850 TnyFolder *src_folder = NULL;
851 TnyFolderType folder_type;
852 folder = tny_msg_get_folder (info->draft_msg);
853 if (folder == NULL) goto end;
854 folder_type = modest_tny_folder_guess_folder_type (folder);
856 if (folder_type == TNY_FOLDER_TYPE_INVALID)
857 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
859 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
860 src_folder = outbox_folder;
862 src_folder = draft_folder;
864 /* Note: This can fail (with a warning) if the message is not really already in a folder,
865 * because this function requires it to have a UID. */
866 header = tny_msg_get_header (info->draft_msg);
867 tny_folder_remove_msg (src_folder, header, NULL);
869 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
870 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
872 g_object_unref (header);
873 g_object_unref (folder);
880 g_object_unref (info->draft_msg);
882 g_object_unref (draft_folder);
884 g_object_unref (outbox_folder);
885 if (info->transport_account)
886 g_object_unref (info->transport_account);
887 g_slice_free (SendNewMailInfo, info);
891 modest_mail_operation_send_new_mail (ModestMailOperation *self,
892 TnyTransportAccount *transport_account,
894 const gchar *from, const gchar *to,
895 const gchar *cc, const gchar *bcc,
896 const gchar *subject, const gchar *plain_body,
897 const gchar *html_body,
898 const GList *attachments_list,
899 const GList *images_list,
900 TnyHeaderFlags priority_flags)
902 ModestMailOperationPrivate *priv = NULL;
903 SendNewMailInfo *info;
905 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
906 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
908 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
909 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
910 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
911 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
913 /* Check parametters */
915 /* Set status failed and set an error */
916 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
917 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
918 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
919 _("Error trying to send a mail. You need to set at least one recipient"));
922 info = g_slice_new0 (SendNewMailInfo);
923 info->transport_account = transport_account;
924 if (transport_account)
925 g_object_ref (transport_account);
926 info->draft_msg = draft_msg;
928 g_object_ref (draft_msg);
931 modest_mail_operation_notify_start (self);
932 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
933 attachments_list, images_list, priority_flags,
934 modest_mail_operation_send_new_mail_cb, info);
940 TnyTransportAccount *transport_account;
942 SaveToDraftstCallback callback;
946 ModestMailOperation *mailop;
947 } SaveToDraftsAddMsgInfo;
950 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
955 ModestMailOperationPrivate *priv = NULL;
956 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
958 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
961 g_warning ("%s: priv->error != NULL", __FUNCTION__);
962 g_error_free(priv->error);
965 priv->error = (err == NULL) ? NULL : g_error_copy(err);
967 if ((!priv->error) && (info->draft_msg != NULL)) {
968 TnyHeader *header = tny_msg_get_header (info->draft_msg);
969 TnyFolder *src_folder = tny_header_get_folder (header);
971 /* Remove the old draft */
972 tny_folder_remove_msg (src_folder, header, NULL);
974 /* Synchronize to expunge and to update the msg counts */
975 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
976 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
978 g_object_unref (G_OBJECT(header));
979 g_object_unref (G_OBJECT(src_folder));
983 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
985 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
987 /* Call the user callback */
989 info->callback (info->mailop, info->msg, info->user_data);
991 if (info->transport_account)
992 g_object_unref (G_OBJECT(info->transport_account));
994 g_object_unref (G_OBJECT (info->draft_msg));
996 g_object_unref (G_OBJECT(info->drafts));
998 g_object_unref (G_OBJECT (info->msg));
999 g_slice_free (SaveToDraftsAddMsgInfo, info);
1001 modest_mail_operation_notify_end (info->mailop);
1002 g_object_unref(info->mailop);
1007 TnyTransportAccount *transport_account;
1009 SaveToDraftstCallback callback;
1014 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1018 TnyFolder *drafts = NULL;
1019 ModestMailOperationPrivate *priv = NULL;
1020 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1022 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1025 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1026 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1027 "modest: failed to create a new msg\n");
1029 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1030 TNY_FOLDER_TYPE_DRAFTS);
1032 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1033 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1034 "modest: failed to create a new msg\n");
1039 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1040 cb_info->transport_account = g_object_ref(info->transport_account);
1041 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1042 cb_info->callback = info->callback;
1043 cb_info->user_data = info->user_data;
1044 cb_info->drafts = g_object_ref(drafts);
1045 cb_info->msg = g_object_ref(msg);
1046 cb_info->mailop = g_object_ref(self);
1047 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1050 /* Call the user callback */
1051 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1053 info->callback (self, msg, info->user_data);
1054 modest_mail_operation_notify_end (self);
1058 g_object_unref (G_OBJECT(drafts));
1059 if (info->draft_msg)
1060 g_object_unref (G_OBJECT (info->draft_msg));
1061 if (info->transport_account)
1062 g_object_unref (G_OBJECT(info->transport_account));
1063 g_slice_free (SaveToDraftsInfo, info);
1067 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1068 TnyTransportAccount *transport_account,
1070 const gchar *from, const gchar *to,
1071 const gchar *cc, const gchar *bcc,
1072 const gchar *subject, const gchar *plain_body,
1073 const gchar *html_body,
1074 const GList *attachments_list,
1075 const GList *images_list,
1076 TnyHeaderFlags priority_flags,
1077 SaveToDraftstCallback callback,
1080 ModestMailOperationPrivate *priv = NULL;
1081 SaveToDraftsInfo *info = NULL;
1083 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1084 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1086 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1088 /* Get account and set it into mail_operation */
1089 priv->account = g_object_ref (transport_account);
1090 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1092 info = g_slice_new0 (SaveToDraftsInfo);
1093 info->transport_account = g_object_ref (transport_account);
1094 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1095 info->callback = callback;
1096 info->user_data = user_data;
1098 modest_mail_operation_notify_start (self);
1099 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1100 attachments_list, images_list, priority_flags,
1101 modest_mail_operation_save_to_drafts_cb, info);
1106 ModestMailOperation *mail_op;
1107 TnyMimePart *mime_part;
1109 GetMimePartSizeCallback callback;
1111 } GetMimePartSizeInfo;
1113 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1114 /* We use this folder observer to track the headers that have been
1115 * added to a folder */
1118 TnyList *new_headers;
1119 } InternalFolderObserver;
1122 GObjectClass parent;
1123 } InternalFolderObserverClass;
1125 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1127 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1128 internal_folder_observer,
1130 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1134 foreach_add_item (gpointer header, gpointer user_data)
1136 tny_list_prepend (TNY_LIST (user_data),
1137 g_object_ref (G_OBJECT (header)));
1140 /* This is the method that looks for new messages in a folder */
1142 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1144 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1146 TnyFolderChangeChanged changed;
1148 changed = tny_folder_change_get_changed (change);
1150 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1153 /* Get added headers */
1154 list = tny_simple_list_new ();
1155 tny_folder_change_get_added_headers (change, list);
1157 /* Add them to the folder observer */
1158 tny_list_foreach (list, foreach_add_item,
1159 derived->new_headers);
1161 g_object_unref (G_OBJECT (list));
1166 internal_folder_observer_init (InternalFolderObserver *self)
1168 self->new_headers = tny_simple_list_new ();
1171 internal_folder_observer_finalize (GObject *object)
1173 InternalFolderObserver *self;
1175 self = (InternalFolderObserver *) object;
1176 g_object_unref (self->new_headers);
1178 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1181 tny_folder_observer_init (TnyFolderObserverIface *iface)
1183 iface->update_func = internal_folder_observer_update;
1186 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1188 GObjectClass *object_class;
1190 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1191 object_class = (GObjectClass*) klass;
1192 object_class->finalize = internal_folder_observer_finalize;
1197 ModestMailOperation *mail_op;
1198 gchar *account_name;
1199 UpdateAccountCallback callback;
1204 TnyFolderObserver *inbox_observer;
1205 guint update_timeout;
1206 } UpdateAccountInfo;
1210 destroy_update_account_info (UpdateAccountInfo *info)
1212 if (info->update_timeout) {
1213 g_source_remove (info->update_timeout);
1214 info->update_timeout = 0;
1217 g_free (info->account_name);
1218 g_object_unref (info->folders);
1219 g_object_unref (info->mail_op);
1220 g_slice_free (UpdateAccountInfo, info);
1224 update_account_get_msg_async_cb (TnyFolder *folder,
1230 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1232 /* Just delete the helper. Don't do anything with the new
1233 msg. There is also no need to check for errors */
1234 g_object_unref (msg_info->mail_op);
1235 g_object_unref (msg_info->header);
1236 g_slice_free (GetMsgInfo, msg_info);
1241 inbox_refreshed_cb (TnyFolder *inbox,
1246 UpdateAccountInfo *info;
1247 ModestMailOperationPrivate *priv;
1248 TnyIterator *new_headers_iter;
1249 GPtrArray *new_headers_array = NULL;
1250 gint max_size, retrieve_limit, i;
1251 ModestAccountMgr *mgr;
1252 gchar *retrieve_type = NULL;
1253 TnyList *new_headers = NULL;
1254 gboolean headers_only;
1255 TnyTransportAccount *transport_account;
1256 ModestTnySendQueue *send_queue;
1258 info = (UpdateAccountInfo *) user_data;
1259 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1260 mgr = modest_runtime_get_account_mgr ();
1262 if (canceled || err || !inbox) {
1263 /* Try to send anyway */
1267 /* Get the message max size */
1268 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1269 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1271 max_size = G_MAXINT;
1273 max_size = max_size * KB;
1275 /* Create the new headers array. We need it to sort the
1276 new headers by date */
1277 new_headers_array = g_ptr_array_new ();
1278 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1279 while (!tny_iterator_is_done (new_headers_iter)) {
1280 TnyHeader *header = NULL;
1282 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1283 /* Apply per-message size limits */
1284 if (tny_header_get_message_size (header) < max_size)
1285 g_ptr_array_add (new_headers_array, g_object_ref (header));
1287 g_object_unref (header);
1288 tny_iterator_next (new_headers_iter);
1290 g_object_unref (new_headers_iter);
1291 tny_folder_remove_observer (inbox, info->inbox_observer);
1292 g_object_unref (info->inbox_observer);
1293 info->inbox_observer = NULL;
1295 /* Update the last updated key, even if we don't have to get new headers */
1296 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1298 if (new_headers_array->len == 0)
1301 /* Get per-account message amount retrieval limit */
1302 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1303 if (retrieve_limit == 0)
1304 retrieve_limit = G_MAXINT;
1306 /* Get per-account retrieval type */
1307 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1308 headers_only = !g_ascii_strcasecmp (retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_HEADERS_ONLY);
1309 g_free (retrieve_type);
1312 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1314 /* TODO: Ask the user, instead of just failing,
1315 * showing mail_nc_msg_count_limit_exceeded, with 'Get
1316 * all' and 'Newest only' buttons. */
1317 if (new_headers_array->len > retrieve_limit) {
1321 if (!headers_only) {
1323 const gint msg_list_size = compute_message_array_size (new_headers_array);
1326 priv->total = MIN (new_headers_array->len, retrieve_limit);
1327 while (msg_num < priv->total) {
1328 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1329 TnyFolder *folder = tny_header_get_folder (header);
1330 GetMsgInfo *msg_info;
1332 /* Create the message info */
1333 msg_info = g_slice_new0 (GetMsgInfo);
1334 msg_info->mail_op = g_object_ref (info->mail_op);
1335 msg_info->header = g_object_ref (header);
1336 msg_info->total_bytes = msg_list_size;
1338 /* Get message in an async way */
1339 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1340 get_msg_status_cb, msg_info);
1342 g_object_unref (folder);
1348 /* Copy the headers to a list and free the array */
1349 new_headers = tny_simple_list_new ();
1350 for (i=0; i < new_headers_array->len; i++) {
1351 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1352 tny_list_append (new_headers, G_OBJECT (header));
1354 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1355 g_ptr_array_free (new_headers_array, FALSE);
1362 /* Get the transport account */
1363 transport_account = (TnyTransportAccount *)
1364 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1365 info->account_name);
1368 send_queue = modest_runtime_get_send_queue (transport_account);
1369 modest_tny_send_queue_try_to_send (send_queue);
1371 /* Check if the operation was a success */
1373 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1375 /* Set the account back to not busy */
1376 modest_account_mgr_set_account_busy (mgr, info->account_name, FALSE);
1378 /* Call the user callback */
1380 info->callback (info->mail_op, new_headers, info->user_data);
1382 /* Notify about operation end */
1383 modest_mail_operation_notify_end (info->mail_op);
1387 g_object_unref (new_headers);
1388 destroy_update_account_info (info);
1392 recurse_folders_async_cb (TnyFolderStore *folder_store,
1398 UpdateAccountInfo *info;
1399 ModestMailOperationPrivate *priv;
1401 info = (UpdateAccountInfo *) user_data;
1402 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1404 if (err || canceled) {
1405 /* Try to continue anyway */
1407 TnyIterator *iter = tny_list_create_iterator (list);
1408 while (!tny_iterator_is_done (iter)) {
1409 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1410 TnyList *folders = tny_simple_list_new ();
1412 /* Add to the list of all folders */
1413 tny_list_append (info->folders, (GObject *) folder);
1415 /* Add pending call */
1416 info->pending_calls++;
1418 tny_folder_store_get_folders_async (folder, folders, recurse_folders_async_cb,
1421 g_object_unref (G_OBJECT (folder));
1423 tny_iterator_next (iter);
1425 g_object_unref (G_OBJECT (iter));
1426 g_object_unref (G_OBJECT (list));
1429 /* Remove my own pending call */
1430 info->pending_calls--;
1432 /* This means that we have all the folders */
1433 if (info->pending_calls == 0) {
1434 TnyIterator *iter_all_folders;
1435 TnyFolder *inbox = NULL;
1437 iter_all_folders = tny_list_create_iterator (info->folders);
1439 /* Do a poke status over all folders */
1440 while (!tny_iterator_is_done (iter_all_folders) &&
1441 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1442 TnyFolder *folder = NULL;
1444 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1446 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1447 /* Get a reference to the INBOX */
1448 inbox = g_object_ref (folder);
1450 /* Issue a poke status over the folder */
1452 tny_folder_poke_status (folder);
1455 /* Free and go to next */
1456 g_object_unref (folder);
1457 tny_iterator_next (iter_all_folders);
1459 g_object_unref (iter_all_folders);
1461 /* Stop the progress notification */
1462 g_source_remove (info->update_timeout);
1463 info->update_timeout = 0;
1465 /* Refresh the INBOX */
1467 /* Refresh the folder. Our observer receives
1468 * the new emails during folder refreshes, so
1469 * we can use observer->new_headers
1471 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1472 tny_folder_add_observer (inbox, info->inbox_observer);
1474 /* Refresh the INBOX */
1475 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1476 g_object_unref (inbox);
1478 /* We could not perform the inbox refresh but
1479 we'll try to send mails anyway */
1480 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1486 * Issues the "progress-changed" signal. The timer won't be removed,
1487 * so you must call g_source_remove to stop the signal emission
1490 timeout_notify_progress (gpointer data)
1492 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1493 ModestMailOperationState *state;
1495 state = modest_mail_operation_clone_state (mail_op);
1497 /* This is a GDK lock because we are an idle callback and
1498 * the handlers of this signal can contain Gtk+ code */
1500 gdk_threads_enter (); /* CHECKED */
1501 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1502 gdk_threads_leave (); /* CHECKED */
1504 g_slice_free (ModestMailOperationState, state);
1510 modest_mail_operation_update_account (ModestMailOperation *self,
1511 const gchar *account_name,
1513 UpdateAccountCallback callback,
1516 UpdateAccountInfo *info = NULL;
1517 ModestMailOperationPrivate *priv = NULL;
1518 ModestTnyAccountStore *account_store = NULL;
1519 TnyStoreAccount *store_account = NULL;
1522 /* Init mail operation */
1523 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1526 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1527 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1529 /* Get the store account */
1530 account_store = modest_runtime_get_account_store ();
1531 store_account = (TnyStoreAccount *)
1532 modest_tny_account_store_get_server_account (account_store,
1534 TNY_ACCOUNT_TYPE_STORE);
1535 priv->account = g_object_ref (store_account);
1537 /* Create the helper object */
1538 info = g_slice_new0 (UpdateAccountInfo);
1539 info->pending_calls = 1;
1540 info->folders = tny_simple_list_new ();
1541 info->mail_op = g_object_ref (self);
1542 info->poke_all = poke_all;
1543 info->account_name = g_strdup (account_name);
1544 info->callback = callback;
1545 info->user_data = user_data;
1546 info->update_timeout = g_timeout_add (250, timeout_notify_progress, self);
1548 /* Set account busy */
1549 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1550 modest_mail_operation_notify_start (self);
1552 /* Get all folders and continue in the callback */
1553 folders = tny_simple_list_new ();
1554 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (store_account),
1555 folders, recurse_folders_async_cb,
1560 * Used to notify the queue from the main
1561 * loop. We call it inside an idle call to achieve that
1564 idle_notify_queue (gpointer data)
1566 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1568 gdk_threads_enter ();
1569 modest_mail_operation_notify_end (mail_op);
1570 gdk_threads_leave ();
1571 g_object_unref (mail_op);
1577 compare_headers_by_date (gconstpointer a,
1580 TnyHeader **header1, **header2;
1581 time_t sent1, sent2;
1583 header1 = (TnyHeader **) a;
1584 header2 = (TnyHeader **) b;
1586 sent1 = tny_header_get_date_sent (*header1);
1587 sent2 = tny_header_get_date_sent (*header2);
1589 /* We want the most recent ones (greater time_t) at the
1598 /* ******************************************************************* */
1599 /* ************************** STORE ACTIONS ************************* */
1600 /* ******************************************************************* */
1604 modest_mail_operation_create_folder (ModestMailOperation *self,
1605 TnyFolderStore *parent,
1608 ModestMailOperationPrivate *priv;
1609 TnyFolder *new_folder = NULL;
1611 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1612 g_return_val_if_fail (name, NULL);
1614 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1615 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1616 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1617 g_object_ref (parent) :
1618 modest_tny_folder_get_account (TNY_FOLDER (parent));
1620 /* Check for already existing folder */
1621 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1622 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1623 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1624 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1625 _CS("ckdg_ib_folder_already_exists"));
1629 if (TNY_IS_FOLDER (parent)) {
1630 /* Check folder rules */
1631 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1632 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1633 /* Set status failed and set an error */
1634 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1635 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1636 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1637 _("mail_in_ui_folder_create_error"));
1641 if (!strcmp (name, " ") || strchr (name, '/')) {
1642 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1643 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1644 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1645 _("mail_in_ui_folder_create_error"));
1649 /* Create the folder */
1650 modest_mail_operation_notify_start (self);
1651 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1652 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1654 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1657 /* Notify about operation end */
1658 modest_mail_operation_notify_end (self);
1664 modest_mail_operation_remove_folder (ModestMailOperation *self,
1666 gboolean remove_to_trash)
1668 TnyAccount *account;
1669 ModestMailOperationPrivate *priv;
1670 ModestTnyFolderRules rules;
1672 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1673 g_return_if_fail (TNY_IS_FOLDER (folder));
1675 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1677 /* Check folder rules */
1678 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1679 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1680 /* Set status failed and set an error */
1681 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1682 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1683 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1684 _("mail_in_ui_folder_delete_error"));
1688 /* Get the account */
1689 account = modest_tny_folder_get_account (folder);
1690 priv->account = g_object_ref(account);
1691 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1693 /* Delete folder or move to trash */
1694 if (remove_to_trash) {
1695 TnyFolder *trash_folder = NULL;
1696 trash_folder = modest_tny_account_get_special_folder (account,
1697 TNY_FOLDER_TYPE_TRASH);
1698 /* TODO: error_handling */
1700 modest_mail_operation_notify_start (self);
1701 modest_mail_operation_xfer_folder (self, folder,
1702 TNY_FOLDER_STORE (trash_folder),
1704 g_object_unref (trash_folder);
1707 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1709 modest_mail_operation_notify_start (self);
1710 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1711 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1714 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1716 g_object_unref (parent);
1718 g_warning ("%s: could not get parent folder", __FUNCTION__);
1720 g_object_unref (G_OBJECT (account));
1723 /* Notify about operation end */
1724 modest_mail_operation_notify_end (self);
1728 transfer_folder_status_cb (GObject *obj,
1732 ModestMailOperation *self;
1733 ModestMailOperationPrivate *priv;
1734 ModestMailOperationState *state;
1735 XFerMsgAsyncHelper *helper;
1737 g_return_if_fail (status != NULL);
1738 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1740 helper = (XFerMsgAsyncHelper *) user_data;
1741 g_return_if_fail (helper != NULL);
1743 self = helper->mail_op;
1744 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1746 priv->done = status->position;
1747 priv->total = status->of_total;
1749 state = modest_mail_operation_clone_state (self);
1751 /* This is not a GDK lock because we are a Tinymail callback
1752 * which is already GDK locked by Tinymail */
1754 /* no gdk_threads_enter (), CHECKED */
1756 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1758 /* no gdk_threads_leave (), CHECKED */
1760 g_slice_free (ModestMailOperationState, state);
1765 transfer_folder_cb (TnyFolder *folder,
1767 TnyFolderStore *into,
1768 TnyFolder *new_folder,
1772 XFerMsgAsyncHelper *helper;
1773 ModestMailOperation *self = NULL;
1774 ModestMailOperationPrivate *priv = NULL;
1776 helper = (XFerMsgAsyncHelper *) user_data;
1777 g_return_if_fail (helper != NULL);
1779 self = helper->mail_op;
1780 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1783 priv->error = g_error_copy (err);
1785 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1786 } else if (cancelled) {
1787 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1788 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1789 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1790 _("Transference of %s was cancelled."),
1791 tny_folder_get_name (folder));
1794 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1797 /* Notify about operation end */
1798 modest_mail_operation_notify_end (self);
1800 /* If user defined callback function was defined, call it */
1801 if (helper->user_callback) {
1803 /* This is not a GDK lock because we are a Tinymail callback
1804 * which is already GDK locked by Tinymail */
1806 /* no gdk_threads_enter (), CHECKED */
1807 helper->user_callback (self, helper->user_data);
1808 /* no gdk_threads_leave () , CHECKED */
1812 g_object_unref (helper->mail_op);
1813 g_slice_free (XFerMsgAsyncHelper, helper);
1818 * This function checks if the new name is a valid name for our local
1819 * folders account. The new name could not be the same than then name
1820 * of any of the mandatory local folders
1822 * We can not rely on tinymail because tinymail does not check the
1823 * name of the virtual folders that the account could have in the case
1824 * that we're doing a rename (because it directly calls Camel which
1825 * knows nothing about our virtual folders).
1827 * In the case of an actual copy/move (i.e. move/copy a folder between
1828 * accounts) tinymail uses the tny_folder_store_create_account which
1829 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1830 * checks the new name of the folder, so this call in that case
1831 * wouldn't be needed. *But* NOTE that if tinymail changes its
1832 * implementation (if folder transfers within the same account is no
1833 * longer implemented as a rename) this call will allow Modest to work
1836 * If the new name is not valid, this function will set the status to
1837 * failed and will set also an error in the mail operation
1840 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1841 TnyFolderStore *into,
1842 const gchar *new_name)
1844 if (TNY_IS_ACCOUNT (into) &&
1845 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1846 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1848 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1849 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1850 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1851 _CS("ckdg_ib_folder_already_exists"));
1858 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1860 TnyFolderStore *parent,
1861 gboolean delete_original,
1862 XferAsyncUserCallback user_callback,
1865 ModestMailOperationPrivate *priv = NULL;
1866 ModestTnyFolderRules parent_rules = 0, rules;
1867 XFerMsgAsyncHelper *helper = NULL;
1868 const gchar *folder_name = NULL;
1869 const gchar *error_msg;
1871 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1872 g_return_if_fail (TNY_IS_FOLDER (folder));
1873 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1875 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1876 folder_name = tny_folder_get_name (folder);
1878 /* Set the error msg */
1879 error_msg = _("mail_in_ui_folder_move_target_error");
1881 /* Get account and set it into mail_operation */
1882 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1883 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1884 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1886 /* Get folder rules */
1887 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1888 if (TNY_IS_FOLDER (parent))
1889 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1891 /* Apply operation constraints */
1892 if ((gpointer) parent == (gpointer) folder ||
1893 (!TNY_IS_FOLDER_STORE (parent)) ||
1894 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1897 } else if (TNY_IS_FOLDER (parent) &&
1898 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1902 } else if (TNY_IS_FOLDER (parent) &&
1903 TNY_IS_FOLDER_STORE (folder) &&
1904 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1905 TNY_FOLDER_STORE (folder))) {
1906 /* Do not move a parent into a child */
1908 } else if (TNY_IS_FOLDER_STORE (parent) &&
1909 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
1910 /* Check that the new folder name is not used by any
1913 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1914 /* Check that the new folder name is not used by any
1915 special local folder */
1918 /* Create the helper */
1919 helper = g_slice_new0 (XFerMsgAsyncHelper);
1920 helper->mail_op = g_object_ref (self);
1921 helper->dest_folder = NULL;
1922 helper->headers = NULL;
1923 helper->user_callback = user_callback;
1924 helper->user_data = user_data;
1926 /* Move/Copy folder */
1927 modest_mail_operation_notify_start (self);
1928 tny_folder_copy_async (folder,
1930 tny_folder_get_name (folder),
1933 transfer_folder_status_cb,
1939 /* Set status failed and set an error */
1940 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1941 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1942 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1945 /* Call the user callback if exists */
1947 user_callback (self, user_data);
1949 /* Notify the queue */
1950 modest_mail_operation_notify_end (self);
1954 modest_mail_operation_rename_folder (ModestMailOperation *self,
1958 ModestMailOperationPrivate *priv;
1959 ModestTnyFolderRules rules;
1960 XFerMsgAsyncHelper *helper;
1962 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1963 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1964 g_return_if_fail (name);
1966 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1968 /* Get account and set it into mail_operation */
1969 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1970 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1972 /* Check folder rules */
1973 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1974 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1975 /* Set status failed and set an error */
1976 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1977 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1978 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1979 _("FIXME: unable to rename"));
1981 /* Notify about operation end */
1982 modest_mail_operation_notify_end (self);
1983 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1984 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1985 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1986 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1987 _("FIXME: unable to rename"));
1988 /* Notify about operation end */
1989 modest_mail_operation_notify_end (self);
1991 TnyFolderStore *into;
1993 into = tny_folder_get_folder_store (folder);
1995 /* Check that the new folder name is not used by any
1996 special local folder */
1997 if (new_name_valid_if_local_account (priv, into, name)) {
1998 /* Create the helper */
1999 helper = g_slice_new0 (XFerMsgAsyncHelper);
2000 helper->mail_op = g_object_ref(self);
2001 helper->dest_folder = NULL;
2002 helper->headers = NULL;
2003 helper->user_callback = NULL;
2004 helper->user_data = NULL;
2006 /* Rename. Camel handles folder subscription/unsubscription */
2007 modest_mail_operation_notify_start (self);
2008 tny_folder_copy_async (folder, into, name, TRUE,
2010 transfer_folder_status_cb,
2013 modest_mail_operation_notify_end (self);
2015 g_object_unref (into);
2019 /* ******************************************************************* */
2020 /* ************************** MSG ACTIONS ************************* */
2021 /* ******************************************************************* */
2024 modest_mail_operation_get_msg (ModestMailOperation *self,
2026 GetMsgAsyncUserCallback user_callback,
2029 GetMsgInfo *helper = NULL;
2031 ModestMailOperationPrivate *priv;
2033 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2034 g_return_if_fail (TNY_IS_HEADER (header));
2036 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2037 folder = tny_header_get_folder (header);
2039 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2043 /* Get account and set it into mail_operation */
2044 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2046 /* Check for cached messages */
2047 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2048 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2050 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2052 /* Create the helper */
2053 helper = g_slice_new0 (GetMsgInfo);
2054 helper->header = g_object_ref (header);
2055 helper->mail_op = g_object_ref (self);
2056 helper->user_callback = user_callback;
2057 helper->user_data = user_data;
2058 helper->destroy_notify = NULL;
2059 helper->last_total_bytes = 0;
2060 helper->sum_total_bytes = 0;
2061 helper->total_bytes = tny_header_get_message_size (header);
2063 modest_mail_operation_notify_start (self);
2064 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2066 g_object_unref (G_OBJECT (folder));
2070 get_msg_status_cb (GObject *obj,
2074 GetMsgInfo *helper = NULL;
2076 g_return_if_fail (status != NULL);
2077 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2079 helper = (GetMsgInfo *) user_data;
2080 g_return_if_fail (helper != NULL);
2082 /* Notify progress */
2083 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2084 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2088 get_msg_async_cb (TnyFolder *folder,
2094 GetMsgInfo *info = NULL;
2095 ModestMailOperationPrivate *priv = NULL;
2098 info = (GetMsgInfo *) user_data;
2100 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2102 finished = (priv->done == priv->total) ? TRUE : FALSE;
2105 if (canceled || err) {
2106 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2108 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2109 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2112 /* Set the success status before calling the user callback */
2113 if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2114 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2118 /* Call the user callback */
2119 if (info->user_callback)
2120 info->user_callback (info->mail_op, info->header, canceled,
2121 msg, err, info->user_data);
2123 /* Notify about operation end if this is the last callback */
2125 /* Free user data */
2126 if (info->destroy_notify)
2127 info->destroy_notify (info->user_data);
2129 /* Notify about operation end */
2130 modest_mail_operation_notify_end (info->mail_op);
2134 g_object_unref (info->header);
2135 g_object_unref (info->mail_op);
2136 g_slice_free (GetMsgInfo, info);
2140 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2141 TnyList *header_list,
2142 GetMsgAsyncUserCallback user_callback,
2144 GDestroyNotify notify)
2146 ModestMailOperationPrivate *priv = NULL;
2147 gboolean size_ok = TRUE;
2149 TnyIterator *iter = NULL;
2151 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2153 /* Init mail operation */
2154 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2155 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2156 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2158 priv->total = tny_list_get_length(header_list);
2160 /* Get account and set it into mail_operation */
2161 if (tny_list_get_length (header_list) >= 1) {
2162 iter = tny_list_create_iterator (header_list);
2163 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2165 TnyFolder *folder = tny_header_get_folder (header);
2167 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2168 g_object_unref (folder);
2170 g_object_unref (header);
2173 if (tny_list_get_length (header_list) == 1) {
2174 g_object_unref (iter);
2179 /* Get msg size limit */
2180 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2181 MODEST_CONF_MSG_SIZE_LIMIT,
2184 g_clear_error (&(priv->error));
2185 max_size = G_MAXINT;
2187 max_size = max_size * KB;
2190 /* Check message size limits. If there is only one message
2191 always retrieve it */
2193 while (!tny_iterator_is_done (iter) && size_ok) {
2194 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2196 if (tny_header_get_message_size (header) >= max_size)
2198 g_object_unref (header);
2201 tny_iterator_next (iter);
2203 g_object_unref (iter);
2207 const gint msg_list_size = compute_message_list_size (header_list);
2209 modest_mail_operation_notify_start (self);
2210 iter = tny_list_create_iterator (header_list);
2211 while (!tny_iterator_is_done (iter)) {
2212 GetMsgInfo *msg_info = NULL;
2213 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2214 TnyFolder *folder = tny_header_get_folder (header);
2216 /* Create the message info */
2217 msg_info = g_slice_new0 (GetMsgInfo);
2218 msg_info->mail_op = g_object_ref (self);
2219 msg_info->header = g_object_ref (header);
2220 msg_info->user_callback = user_callback;
2221 msg_info->user_data = user_data;
2222 msg_info->destroy_notify = notify;
2223 msg_info->last_total_bytes = 0;
2224 msg_info->sum_total_bytes = 0;
2225 msg_info->total_bytes = msg_list_size;
2227 /* The callback will call it per each header */
2228 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2230 /* Free and go on */
2231 g_object_unref (header);
2232 g_object_unref (folder);
2233 tny_iterator_next (iter);
2235 g_object_unref (iter);
2237 /* Set status failed and set an error */
2238 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2239 /* FIXME: the error msg is different for pop */
2240 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2241 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2242 _("emev_ni_ui_imap_msg_size_exceed_error"));
2243 /* Remove from queue and free resources */
2244 modest_mail_operation_notify_end (self);
2252 modest_mail_operation_remove_msg (ModestMailOperation *self,
2254 gboolean remove_to_trash /*ignored*/)
2257 ModestMailOperationPrivate *priv;
2259 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2260 g_return_if_fail (TNY_IS_HEADER (header));
2262 if (remove_to_trash)
2263 g_warning ("remove to trash is not implemented");
2265 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2266 folder = tny_header_get_folder (header);
2268 /* Get account and set it into mail_operation */
2269 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2270 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2271 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2273 /* remove message from folder */
2274 tny_folder_remove_msg (folder, header, &(priv->error));
2276 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2277 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2279 modest_mail_operation_notify_start (self);
2281 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2282 TNY_IS_CAMEL_POP_FOLDER (folder))
2283 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> dont expunge */
2285 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2291 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2293 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2296 g_object_unref (G_OBJECT (folder));
2298 /* Notify about operation end */
2299 modest_mail_operation_notify_end (self);
2303 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2305 gboolean remove_to_trash /*ignored*/)
2308 ModestMailOperationPrivate *priv;
2309 TnyIterator *iter = NULL;
2310 TnyHeader *header = NULL;
2311 TnyList *remove_headers = NULL;
2312 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2314 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2315 g_return_if_fail (TNY_IS_LIST (headers));
2317 if (remove_to_trash)
2318 g_warning ("remove to trash is not implemented");
2320 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2322 remove_headers = g_object_ref(headers);
2324 /* Get folder from first header and sync it */
2325 iter = tny_list_create_iterator (headers);
2326 header = TNY_HEADER (tny_iterator_get_current (iter));
2327 folder = tny_header_get_folder (header);
2329 /* Don't remove messages that are being sent */
2330 if (modest_tny_folder_is_local_folder (folder)) {
2331 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2333 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2334 TnyTransportAccount *traccount = NULL;
2335 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2336 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2338 ModestTnySendQueueStatus status;
2339 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2340 TnyIterator *iter = tny_list_create_iterator(headers);
2341 g_object_unref(remove_headers);
2342 remove_headers = TNY_LIST(tny_simple_list_new());
2343 while (!tny_iterator_is_done(iter)) {
2345 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2346 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2347 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2348 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2349 tny_list_append(remove_headers, G_OBJECT(hdr));
2351 g_object_unref(hdr);
2353 tny_iterator_next(iter);
2355 g_object_unref(iter);
2356 g_object_unref(traccount);
2360 /* Get account and set it into mail_operation */
2361 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2362 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2363 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2365 /* remove message from folder */
2366 modest_mail_operation_notify_start (self);
2368 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2370 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2371 TNY_IS_CAMEL_POP_FOLDER (folder))
2372 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> don't expunge */
2375 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2381 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2383 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2386 g_object_unref (remove_headers);
2387 g_object_unref (header);
2388 g_object_unref (iter);
2389 g_object_unref (G_OBJECT (folder));
2391 /* Notify about operation end */
2392 modest_mail_operation_notify_end (self);
2396 notify_progress_of_multiple_messages (ModestMailOperation *self,
2398 gint *last_total_bytes,
2399 gint *sum_total_bytes,
2401 gboolean increment_done)
2403 ModestMailOperationPrivate *priv;
2404 ModestMailOperationState *state;
2405 gboolean is_num_bytes;
2407 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2409 /* We know that tinymail sends us information about
2410 transferred bytes with this particular message */
2411 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2413 state = modest_mail_operation_clone_state (self);
2414 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2415 /* We know that we're in a different message when the
2416 total number of bytes to transfer is different. Of
2417 course it could fail if we're transferring messages
2418 of the same size, but this is a workarround */
2419 if (status->of_total != *last_total_bytes) {
2420 /* We need to increment the done when there is
2421 no information about each individual
2422 message, we need to do this in message
2423 transfers, and we don't do it for getting
2427 *sum_total_bytes += *last_total_bytes;
2428 *last_total_bytes = status->of_total;
2430 state->bytes_done += status->position + *sum_total_bytes;
2431 state->bytes_total = total_bytes;
2433 /* Notify the status change. Only notify about changes
2434 referred to bytes */
2435 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2439 g_slice_free (ModestMailOperationState, state);
2443 transfer_msgs_status_cb (GObject *obj,
2447 XFerMsgAsyncHelper *helper;
2449 g_return_if_fail (status != NULL);
2450 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2452 helper = (XFerMsgAsyncHelper *) user_data;
2453 g_return_if_fail (helper != NULL);
2455 /* Notify progress */
2456 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2457 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2462 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2464 XFerMsgAsyncHelper *helper;
2465 ModestMailOperation *self;
2466 ModestMailOperationPrivate *priv;
2467 TnyIterator *iter = NULL;
2468 TnyHeader *header = NULL;
2470 helper = (XFerMsgAsyncHelper *) user_data;
2471 self = helper->mail_op;
2473 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2476 priv->error = g_error_copy (err);
2478 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2479 } else if (cancelled) {
2480 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2481 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2482 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2483 _("Error trying to refresh the contents of %s"),
2484 tny_folder_get_name (folder));
2487 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2489 /* Update folder counts */
2490 tny_folder_poke_status (folder);
2491 tny_folder_poke_status (helper->dest_folder);
2495 /* Mark headers as deleted and seen */
2496 if ((helper->delete) &&
2497 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2498 iter = tny_list_create_iterator (helper->headers);
2499 while (!tny_iterator_is_done (iter)) {
2500 header = TNY_HEADER (tny_iterator_get_current (iter));
2501 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2502 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2503 g_object_unref (header);
2505 tny_iterator_next (iter);
2511 /* Notify about operation end */
2512 modest_mail_operation_notify_end (self);
2514 /* If user defined callback function was defined, call it */
2515 if (helper->user_callback) {
2516 /* This is not a GDK lock because we are a Tinymail callback and
2517 * Tinymail already acquires the Gdk lock */
2519 /* no gdk_threads_enter (), CHECKED */
2520 helper->user_callback (self, helper->user_data);
2521 /* no gdk_threads_leave (), CHECKED */
2525 if (helper->headers)
2526 g_object_unref (helper->headers);
2527 if (helper->dest_folder)
2528 g_object_unref (helper->dest_folder);
2529 if (helper->mail_op)
2530 g_object_unref (helper->mail_op);
2532 g_object_unref (folder);
2534 g_object_unref (iter);
2535 g_slice_free (XFerMsgAsyncHelper, helper);
2539 compute_message_list_size (TnyList *headers)
2544 iter = tny_list_create_iterator (headers);
2545 while (!tny_iterator_is_done (iter)) {
2546 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2547 size += tny_header_get_message_size (header);
2548 g_object_unref (header);
2549 tny_iterator_next (iter);
2551 g_object_unref (iter);
2557 compute_message_array_size (GPtrArray *headers)
2562 for (i = 0; i < headers->len; i++) {
2563 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2564 size += tny_header_get_message_size (header);
2572 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2575 gboolean delete_original,
2576 XferAsyncUserCallback user_callback,
2579 ModestMailOperationPrivate *priv = NULL;
2580 TnyIterator *iter = NULL;
2581 TnyFolder *src_folder = NULL;
2582 XFerMsgAsyncHelper *helper = NULL;
2583 TnyHeader *header = NULL;
2584 ModestTnyFolderRules rules = 0;
2586 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2587 g_return_if_fail (headers && TNY_IS_LIST (headers));
2588 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2590 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2591 priv->total = tny_list_get_length (headers);
2593 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2594 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2596 /* Apply folder rules */
2597 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2598 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2599 /* Set status failed and set an error */
2600 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2601 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2602 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2603 _CS("ckct_ib_unable_to_paste_here"));
2604 /* Notify the queue */
2605 modest_mail_operation_notify_end (self);
2609 /* Get source folder */
2610 iter = tny_list_create_iterator (headers);
2611 header = TNY_HEADER (tny_iterator_get_current (iter));
2613 src_folder = tny_header_get_folder (header);
2614 g_object_unref (header);
2616 g_object_unref (iter);
2618 if (src_folder == NULL) {
2619 /* Notify the queue */
2620 modest_mail_operation_notify_end (self);
2622 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2627 /* Check folder source and destination */
2628 if (src_folder == folder) {
2629 /* Set status failed and set an error */
2630 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2631 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2632 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2633 _("mail_in_ui_folder_copy_target_error"));
2635 /* Notify the queue */
2636 modest_mail_operation_notify_end (self);
2639 g_object_unref (src_folder);
2643 /* Create the helper */
2644 helper = g_slice_new0 (XFerMsgAsyncHelper);
2645 helper->mail_op = g_object_ref(self);
2646 helper->dest_folder = g_object_ref(folder);
2647 helper->headers = g_object_ref(headers);
2648 helper->user_callback = user_callback;
2649 helper->user_data = user_data;
2650 helper->delete = delete_original;
2651 helper->last_total_bytes = 0;
2652 helper->sum_total_bytes = 0;
2653 helper->total_bytes = compute_message_list_size (headers);
2655 /* Get account and set it into mail_operation */
2656 priv->account = modest_tny_folder_get_account (src_folder);
2658 /* Transfer messages */
2659 modest_mail_operation_notify_start (self);
2660 tny_folder_transfer_msgs_async (src_folder,
2665 transfer_msgs_status_cb,
2671 on_refresh_folder (TnyFolder *folder,
2676 RefreshAsyncHelper *helper = NULL;
2677 ModestMailOperation *self = NULL;
2678 ModestMailOperationPrivate *priv = NULL;
2680 helper = (RefreshAsyncHelper *) user_data;
2681 self = helper->mail_op;
2682 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2684 g_return_if_fail(priv!=NULL);
2687 priv->error = g_error_copy (error);
2688 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2693 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2694 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2695 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2696 _("Error trying to refresh the contents of %s"),
2697 tny_folder_get_name (folder));
2701 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2704 /* Call user defined callback, if it exists */
2705 if (helper->user_callback) {
2707 /* This is not a GDK lock because we are a Tinymail callback and
2708 * Tinymail already acquires the Gdk lock */
2709 helper->user_callback (self, folder, helper->user_data);
2713 g_slice_free (RefreshAsyncHelper, helper);
2715 /* Notify about operation end */
2716 modest_mail_operation_notify_end (self);
2717 g_object_unref(self);
2721 on_refresh_folder_status_update (GObject *obj,
2725 RefreshAsyncHelper *helper = NULL;
2726 ModestMailOperation *self = NULL;
2727 ModestMailOperationPrivate *priv = NULL;
2728 ModestMailOperationState *state;
2730 g_return_if_fail (user_data != NULL);
2731 g_return_if_fail (status != NULL);
2732 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2734 helper = (RefreshAsyncHelper *) user_data;
2735 self = helper->mail_op;
2736 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2738 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2740 priv->done = status->position;
2741 priv->total = status->of_total;
2743 state = modest_mail_operation_clone_state (self);
2745 /* This is not a GDK lock because we are a Tinymail callback and
2746 * Tinymail already acquires the Gdk lock */
2747 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2749 g_slice_free (ModestMailOperationState, state);
2753 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2755 RefreshAsyncUserCallback user_callback,
2758 ModestMailOperationPrivate *priv = NULL;
2759 RefreshAsyncHelper *helper = NULL;
2761 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2763 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2765 /* Get account and set it into mail_operation */
2766 priv->account = modest_tny_folder_get_account (folder);
2767 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2769 /* Create the helper */
2770 helper = g_slice_new0 (RefreshAsyncHelper);
2771 helper->mail_op = g_object_ref(self);
2772 helper->user_callback = user_callback;
2773 helper->user_data = user_data;
2775 /* Refresh the folder. TODO: tinymail could issue a status
2776 updates before the callback call then this could happen. We
2777 must review the design */
2778 modest_mail_operation_notify_start (self);
2779 tny_folder_refresh_async (folder,
2781 on_refresh_folder_status_update,
2787 modest_mail_operation_notify_start (ModestMailOperation *self)
2789 ModestMailOperationPrivate *priv = NULL;
2791 g_return_if_fail (self);
2793 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2795 /* Ensure that all the fields are filled correctly */
2796 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
2798 /* Notify the observers about the mail operation. We do not
2799 wrapp this emission because we assume that this function is
2800 always called from within the main lock */
2801 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
2806 * It's used by the mail operation queue to notify the observers
2807 * attached to that signal that the operation finished. We need to use
2808 * that because tinymail does not give us the progress of a given
2809 * operation when it finishes (it directly calls the operation
2813 modest_mail_operation_notify_end (ModestMailOperation *self)
2815 ModestMailOperationPrivate *priv = NULL;
2817 g_return_if_fail (self);
2819 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2821 /* Notify the observers about the mail operation end. We do
2822 not wrapp this emission because we assume that this
2823 function is always called from within the main lock */
2824 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
2826 /* Remove the error user data */
2827 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
2828 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
2832 modest_mail_operation_get_account (ModestMailOperation *self)
2834 ModestMailOperationPrivate *priv = NULL;
2836 g_return_val_if_fail (self, NULL);
2838 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2840 return (priv->account) ? g_object_ref (priv->account) : NULL;
2844 modest_mail_operation_noop (ModestMailOperation *self)
2846 ModestMailOperationPrivate *priv = NULL;
2848 g_return_if_fail (self);
2850 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2851 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2852 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2856 /* This mail operation does nothing actually */
2857 modest_mail_operation_notify_start (self);
2858 modest_mail_operation_notify_end (self);