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 if (msg == info->msg) {
652 g_signal_handler_disconnect (queue, info->msg_sent_handler);
653 info->msg_sent_handler = 0;
654 g_signal_handler_disconnect (queue, info->error_happened_handler);
655 info->error_happened_handler = 0;
656 g_object_unref (info->msg);
657 modest_mail_operation_notify_end (info->mail_op);
658 g_object_unref (info->mail_op);
659 g_slice_free (SendMsgInfo, info);
664 send_mail_msg_sent_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
665 guint nth, guint total, gpointer userdata)
667 SendMsgInfo *info = (SendMsgInfo *) info;
669 if (msg == info->msg) {
670 ModestMailOperationPrivate *priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
671 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
674 common_send_mail_operation_end (queue, msg, info);
678 send_mail_error_happened_handler (TnySendQueue *queue, TnyHeader *header, TnyMsg *msg,
679 GError *error, gpointer userdata)
681 SendMsgInfo *info = (SendMsgInfo *) info;
683 if (msg == 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");
691 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));
912 /* Check parametters */
914 /* Set status failed and set an error */
915 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
916 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
917 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
918 _("Error trying to send a mail. You need to set at least one recipient"));
921 info = g_slice_new0 (SendNewMailInfo);
922 info->transport_account = transport_account;
923 if (transport_account)
924 g_object_ref (transport_account);
925 info->draft_msg = draft_msg;
927 g_object_ref (draft_msg);
930 modest_mail_operation_notify_start (self);
931 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
932 attachments_list, images_list, priority_flags,
933 modest_mail_operation_send_new_mail_cb, info);
939 TnyTransportAccount *transport_account;
941 SaveToDraftstCallback callback;
945 ModestMailOperation *mailop;
946 } SaveToDraftsAddMsgInfo;
949 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
954 ModestMailOperationPrivate *priv = NULL;
955 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
957 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
960 g_warning ("%s: priv->error != NULL", __FUNCTION__);
961 g_error_free(priv->error);
964 priv->error = (err == NULL) ? NULL : g_error_copy(err);
966 if ((!priv->error) && (info->draft_msg != NULL)) {
967 TnyHeader *header = tny_msg_get_header (info->draft_msg);
968 TnyFolder *src_folder = tny_header_get_folder (header);
970 /* Remove the old draft */
971 tny_folder_remove_msg (src_folder, header, NULL);
973 /* Synchronize to expunge and to update the msg counts */
974 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
975 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
977 g_object_unref (G_OBJECT(header));
978 g_object_unref (G_OBJECT(src_folder));
982 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
984 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
986 /* Call the user callback */
988 info->callback (info->mailop, info->msg, info->user_data);
990 if (info->transport_account)
991 g_object_unref (G_OBJECT(info->transport_account));
993 g_object_unref (G_OBJECT (info->draft_msg));
995 g_object_unref (G_OBJECT(info->drafts));
997 g_object_unref (G_OBJECT (info->msg));
998 g_slice_free (SaveToDraftsAddMsgInfo, info);
1000 modest_mail_operation_notify_end (info->mailop);
1001 g_object_unref(info->mailop);
1006 TnyTransportAccount *transport_account;
1008 SaveToDraftstCallback callback;
1013 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1017 TnyFolder *drafts = NULL;
1018 ModestMailOperationPrivate *priv = NULL;
1019 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1021 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1024 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1025 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1026 "modest: failed to create a new msg\n");
1028 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1029 TNY_FOLDER_TYPE_DRAFTS);
1031 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1032 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1033 "modest: failed to create a new msg\n");
1038 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1039 cb_info->transport_account = g_object_ref(info->transport_account);
1040 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1041 cb_info->callback = info->callback;
1042 cb_info->user_data = info->user_data;
1043 cb_info->drafts = g_object_ref(drafts);
1044 cb_info->msg = g_object_ref(msg);
1045 cb_info->mailop = g_object_ref(self);
1046 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1049 /* Call the user callback */
1050 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1052 info->callback (self, msg, info->user_data);
1053 modest_mail_operation_notify_end (self);
1057 g_object_unref (G_OBJECT(drafts));
1058 if (info->draft_msg)
1059 g_object_unref (G_OBJECT (info->draft_msg));
1060 if (info->transport_account)
1061 g_object_unref (G_OBJECT(info->transport_account));
1062 g_slice_free (SaveToDraftsInfo, info);
1066 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1067 TnyTransportAccount *transport_account,
1069 const gchar *from, const gchar *to,
1070 const gchar *cc, const gchar *bcc,
1071 const gchar *subject, const gchar *plain_body,
1072 const gchar *html_body,
1073 const GList *attachments_list,
1074 const GList *images_list,
1075 TnyHeaderFlags priority_flags,
1076 SaveToDraftstCallback callback,
1079 ModestMailOperationPrivate *priv = NULL;
1080 SaveToDraftsInfo *info = NULL;
1082 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1083 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1085 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1087 /* Get account and set it into mail_operation */
1088 priv->account = g_object_ref (transport_account);
1089 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1091 info = g_slice_new0 (SaveToDraftsInfo);
1092 info->transport_account = g_object_ref (transport_account);
1093 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1094 info->callback = callback;
1095 info->user_data = user_data;
1097 modest_mail_operation_notify_start (self);
1098 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1099 attachments_list, images_list, priority_flags,
1100 modest_mail_operation_save_to_drafts_cb, info);
1105 ModestMailOperation *mail_op;
1106 TnyMimePart *mime_part;
1108 GetMimePartSizeCallback callback;
1110 } GetMimePartSizeInfo;
1112 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1113 /* We use this folder observer to track the headers that have been
1114 * added to a folder */
1117 TnyList *new_headers;
1118 } InternalFolderObserver;
1121 GObjectClass parent;
1122 } InternalFolderObserverClass;
1124 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1126 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1127 internal_folder_observer,
1129 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1133 foreach_add_item (gpointer header, gpointer user_data)
1135 tny_list_prepend (TNY_LIST (user_data),
1136 g_object_ref (G_OBJECT (header)));
1139 /* This is the method that looks for new messages in a folder */
1141 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1143 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1145 TnyFolderChangeChanged changed;
1147 changed = tny_folder_change_get_changed (change);
1149 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1152 /* Get added headers */
1153 list = tny_simple_list_new ();
1154 tny_folder_change_get_added_headers (change, list);
1156 /* Add them to the folder observer */
1157 tny_list_foreach (list, foreach_add_item,
1158 derived->new_headers);
1160 g_object_unref (G_OBJECT (list));
1165 internal_folder_observer_init (InternalFolderObserver *self)
1167 self->new_headers = tny_simple_list_new ();
1170 internal_folder_observer_finalize (GObject *object)
1172 InternalFolderObserver *self;
1174 self = (InternalFolderObserver *) object;
1175 g_object_unref (self->new_headers);
1177 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1180 tny_folder_observer_init (TnyFolderObserverIface *iface)
1182 iface->update_func = internal_folder_observer_update;
1185 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1187 GObjectClass *object_class;
1189 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1190 object_class = (GObjectClass*) klass;
1191 object_class->finalize = internal_folder_observer_finalize;
1196 ModestMailOperation *mail_op;
1197 gchar *account_name;
1198 UpdateAccountCallback callback;
1203 TnyFolderObserver *inbox_observer;
1204 guint update_timeout;
1205 } UpdateAccountInfo;
1209 destroy_update_account_info (UpdateAccountInfo *info)
1211 if (info->update_timeout) {
1212 g_source_remove (info->update_timeout);
1213 info->update_timeout = 0;
1216 g_free (info->account_name);
1217 g_object_unref (info->folders);
1218 g_object_unref (info->mail_op);
1219 g_slice_free (UpdateAccountInfo, info);
1223 update_account_get_msg_async_cb (TnyFolder *folder,
1229 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1231 /* Just delete the helper. Don't do anything with the new
1232 msg. There is also no need to check for errors */
1233 g_object_unref (msg_info->mail_op);
1234 g_object_unref (msg_info->header);
1235 g_slice_free (GetMsgInfo, msg_info);
1240 inbox_refreshed_cb (TnyFolder *inbox,
1245 UpdateAccountInfo *info;
1246 ModestMailOperationPrivate *priv;
1247 TnyIterator *new_headers_iter;
1248 GPtrArray *new_headers_array = NULL;
1249 gint max_size, retrieve_limit, i;
1250 ModestAccountMgr *mgr;
1251 gchar *retrieve_type = NULL;
1252 TnyList *new_headers = NULL;
1253 gboolean headers_only;
1254 TnyTransportAccount *transport_account;
1255 ModestTnySendQueue *send_queue;
1257 info = (UpdateAccountInfo *) user_data;
1258 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1259 mgr = modest_runtime_get_account_mgr ();
1261 if (canceled || err || !inbox) {
1262 /* Try to send anyway */
1266 /* Get the message max size */
1267 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1268 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1270 max_size = G_MAXINT;
1272 max_size = max_size * KB;
1274 /* Create the new headers array. We need it to sort the
1275 new headers by date */
1276 new_headers_array = g_ptr_array_new ();
1277 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1278 while (!tny_iterator_is_done (new_headers_iter)) {
1279 TnyHeader *header = NULL;
1281 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1282 /* Apply per-message size limits */
1283 if (tny_header_get_message_size (header) < max_size)
1284 g_ptr_array_add (new_headers_array, g_object_ref (header));
1286 g_object_unref (header);
1287 tny_iterator_next (new_headers_iter);
1289 g_object_unref (new_headers_iter);
1290 tny_folder_remove_observer (inbox, info->inbox_observer);
1291 g_object_unref (info->inbox_observer);
1292 info->inbox_observer = NULL;
1294 if (new_headers_array->len == 0)
1297 /* Get per-account message amount retrieval limit */
1298 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1299 if (retrieve_limit == 0)
1300 retrieve_limit = G_MAXINT;
1302 /* Get per-account retrieval type */
1303 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1304 headers_only = !g_ascii_strcasecmp (retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_HEADERS_ONLY);
1305 g_free (retrieve_type);
1308 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1310 /* TODO: Ask the user, instead of just failing,
1311 * showing mail_nc_msg_count_limit_exceeded, with 'Get
1312 * all' and 'Newest only' buttons. */
1313 if (new_headers_array->len > retrieve_limit) {
1317 if (!headers_only) {
1319 const gint msg_list_size = compute_message_array_size (new_headers_array);
1322 priv->total = MIN (new_headers_array->len, retrieve_limit);
1323 while (msg_num < priv->total) {
1324 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1325 TnyFolder *folder = tny_header_get_folder (header);
1326 GetMsgInfo *msg_info;
1328 /* Create the message info */
1329 msg_info = g_slice_new0 (GetMsgInfo);
1330 msg_info->mail_op = g_object_ref (info->mail_op);
1331 msg_info->header = g_object_ref (header);
1332 msg_info->total_bytes = msg_list_size;
1334 /* Get message in an async way */
1335 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1336 get_msg_status_cb, msg_info);
1338 g_object_unref (folder);
1344 /* Copy the headers to a list and free the array */
1345 new_headers = tny_simple_list_new ();
1346 for (i=0; i < new_headers_array->len; i++) {
1347 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1348 tny_list_append (new_headers, G_OBJECT (header));
1350 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1351 g_ptr_array_free (new_headers_array, FALSE);
1353 /* Update the last updated key */
1354 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1361 /* Get the transport account */
1362 transport_account = (TnyTransportAccount *)
1363 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1364 info->account_name);
1367 send_queue = modest_runtime_get_send_queue (transport_account);
1368 modest_tny_send_queue_try_to_send (send_queue);
1370 /* Check if the operation was a success */
1372 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1374 /* Set the account back to not busy */
1375 modest_account_mgr_set_account_busy (mgr, info->account_name, FALSE);
1377 /* Call the user callback */
1379 info->callback (info->mail_op, new_headers, info->user_data);
1381 /* Notify about operation end */
1382 modest_mail_operation_notify_end (info->mail_op);
1386 g_object_unref (new_headers);
1387 destroy_update_account_info (info);
1391 recurse_folders_async_cb (TnyFolderStore *folder_store,
1397 UpdateAccountInfo *info;
1398 ModestMailOperationPrivate *priv;
1400 info = (UpdateAccountInfo *) user_data;
1401 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1403 if (err || canceled) {
1404 /* Try to continue anyway */
1406 TnyIterator *iter = tny_list_create_iterator (list);
1407 while (!tny_iterator_is_done (iter)) {
1408 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1409 TnyList *folders = tny_simple_list_new ();
1411 /* Add to the list of all folders */
1412 tny_list_append (info->folders, (GObject *) folder);
1414 /* Add pending call */
1415 info->pending_calls++;
1417 tny_folder_store_get_folders_async (folder, folders, recurse_folders_async_cb,
1420 g_object_unref (G_OBJECT (folder));
1422 tny_iterator_next (iter);
1424 g_object_unref (G_OBJECT (iter));
1425 g_object_unref (G_OBJECT (list));
1428 /* Remove my own pending call */
1429 info->pending_calls--;
1431 /* This means that we have all the folders */
1432 if (info->pending_calls == 0) {
1433 TnyIterator *iter_all_folders;
1434 TnyFolder *inbox = NULL;
1436 iter_all_folders = tny_list_create_iterator (info->folders);
1438 /* Do a poke status over all folders */
1439 while (!tny_iterator_is_done (iter_all_folders) &&
1440 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1441 TnyFolder *folder = NULL;
1443 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1445 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1446 /* Get a reference to the INBOX */
1447 inbox = g_object_ref (folder);
1449 /* Issue a poke status over the folder */
1451 tny_folder_poke_status (folder);
1454 /* Free and go to next */
1455 g_object_unref (folder);
1456 tny_iterator_next (iter_all_folders);
1458 g_object_unref (iter_all_folders);
1460 /* Stop the progress notification */
1461 g_source_remove (info->update_timeout);
1462 info->update_timeout = 0;
1464 /* Refresh the INBOX */
1466 /* Refresh the folder. Our observer receives
1467 * the new emails during folder refreshes, so
1468 * we can use observer->new_headers
1470 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1471 tny_folder_add_observer (inbox, info->inbox_observer);
1473 /* Refresh the INBOX */
1474 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1475 g_object_unref (inbox);
1477 /* We could not perform the inbox refresh but
1478 we'll try to send mails anyway */
1479 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1485 * Issues the "progress-changed" signal. The timer won't be removed,
1486 * so you must call g_source_remove to stop the signal emission
1489 timeout_notify_progress (gpointer data)
1491 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1492 ModestMailOperationState *state;
1494 state = modest_mail_operation_clone_state (mail_op);
1496 /* This is a GDK lock because we are an idle callback and
1497 * the handlers of this signal can contain Gtk+ code */
1499 gdk_threads_enter (); /* CHECKED */
1500 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1501 gdk_threads_leave (); /* CHECKED */
1503 g_slice_free (ModestMailOperationState, state);
1509 modest_mail_operation_update_account (ModestMailOperation *self,
1510 const gchar *account_name,
1512 UpdateAccountCallback callback,
1515 UpdateAccountInfo *info = NULL;
1516 ModestMailOperationPrivate *priv = NULL;
1517 ModestTnyAccountStore *account_store = NULL;
1518 TnyStoreAccount *store_account = NULL;
1521 /* Init mail operation */
1522 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1525 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1526 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1528 /* Get the store account */
1529 account_store = modest_runtime_get_account_store ();
1530 store_account = (TnyStoreAccount *)
1531 modest_tny_account_store_get_server_account (account_store,
1533 TNY_ACCOUNT_TYPE_STORE);
1534 priv->account = g_object_ref (store_account);
1536 /* Create the helper object */
1537 info = g_slice_new0 (UpdateAccountInfo);
1538 info->pending_calls = 1;
1539 info->folders = tny_simple_list_new ();
1540 info->mail_op = g_object_ref (self);
1541 info->poke_all = poke_all;
1542 info->account_name = g_strdup (account_name);
1543 info->callback = callback;
1544 info->user_data = user_data;
1545 info->update_timeout = g_timeout_add (250, timeout_notify_progress, self);
1547 /* Set account busy */
1548 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1549 modest_mail_operation_notify_start (self);
1551 /* Get all folders and continue in the callback */
1552 folders = tny_simple_list_new ();
1553 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (store_account),
1554 folders, recurse_folders_async_cb,
1559 * Used to notify the queue from the main
1560 * loop. We call it inside an idle call to achieve that
1563 idle_notify_queue (gpointer data)
1565 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1567 gdk_threads_enter ();
1568 modest_mail_operation_notify_end (mail_op);
1569 gdk_threads_leave ();
1570 g_object_unref (mail_op);
1576 compare_headers_by_date (gconstpointer a,
1579 TnyHeader **header1, **header2;
1580 time_t sent1, sent2;
1582 header1 = (TnyHeader **) a;
1583 header2 = (TnyHeader **) b;
1585 sent1 = tny_header_get_date_sent (*header1);
1586 sent2 = tny_header_get_date_sent (*header2);
1588 /* We want the most recent ones (greater time_t) at the
1596 /* static gpointer */
1597 /* update_account_thread (gpointer thr_user_data) */
1599 /* static gboolean first_time = TRUE; */
1600 /* UpdateAccountInfo *info = NULL; */
1601 /* TnyList *all_folders = NULL, *new_headers = NULL; */
1602 /* GPtrArray *new_headers_array = NULL; */
1603 /* TnyIterator *iter = NULL; */
1604 /* ModestMailOperationPrivate *priv = NULL; */
1605 /* ModestTnySendQueue *send_queue = NULL; */
1606 /* gint i = 0, timeout = 0; */
1608 /* info = (UpdateAccountInfo *) thr_user_data; */
1609 /* priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op); */
1611 /* /\* Get account and set it into mail_operation *\/ */
1612 /* priv->account = g_object_ref (info->account); */
1614 /* /\* Get all the folders. We can do it synchronously because */
1615 /* we're already running in a different thread than the UI *\/ */
1616 /* all_folders = get_all_folders_from_account (info->account, &(priv->error)); */
1617 /* if (!all_folders) { */
1618 /* priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED; */
1622 /* /\* Update status and notify. We need to call the notification */
1623 /* with a source function in order to call it from the main */
1624 /* loop. We need that in order not to get into trouble with */
1625 /* Gtk+. We use a timeout in order to provide more status */
1626 /* information, because the sync tinymail call does not */
1627 /* provide it for the moment *\/ */
1628 /* timeout = g_timeout_add (100, idle_notify_progress, info->mail_op); */
1630 /* new_headers_array = g_ptr_array_new (); */
1631 /* iter = tny_list_create_iterator (all_folders); */
1633 /* while (!tny_iterator_is_done (iter) && !priv->error && */
1634 /* priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) { */
1636 /* TnyFolderType folder_type; */
1637 /* TnyFolder *folder = NULL; */
1639 /* folder = TNY_FOLDER (tny_iterator_get_current (iter)); */
1640 /* folder_type = tny_folder_get_folder_type (folder); */
1642 /* /\* Refresh it only if it's the INBOX *\/ */
1643 /* if (folder_type == TNY_FOLDER_TYPE_INBOX) { */
1644 /* InternalFolderObserver *observer = NULL; */
1645 /* TnyIterator *new_headers_iter = NULL; */
1647 /* /\* Refresh the folder. Our observer receives */
1648 /* * the new emails during folder refreshes, so */
1649 /* * we can use observer->new_headers */
1651 /* observer = g_object_new (internal_folder_observer_get_type (), NULL); */
1652 /* tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer)); */
1654 /* tny_folder_refresh (TNY_FOLDER (folder), &(priv->error)); */
1656 /* new_headers_iter = tny_list_create_iterator (observer->new_headers); */
1657 /* while (!tny_iterator_is_done (new_headers_iter)) { */
1658 /* TnyHeader *header = NULL; */
1660 /* header = TNY_HEADER (tny_iterator_get_current (new_headers_iter)); */
1661 /* /\* Apply per-message size limits *\/ */
1662 /* if (tny_header_get_message_size (header) < info->max_size) */
1663 /* g_ptr_array_add (new_headers_array, g_object_ref (header)); */
1665 /* g_object_unref (header); */
1666 /* tny_iterator_next (new_headers_iter); */
1668 /* g_object_unref (new_headers_iter); */
1670 /* tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer)); */
1671 /* g_object_unref (observer); */
1673 /* /\* We no not need to do it the first time, */
1674 /* because it's automatically done by the tree */
1676 /* if (G_LIKELY (!first_time)) */
1677 /* tny_folder_poke_status (folder); */
1679 /* g_object_unref (folder); */
1681 /* tny_iterator_next (iter); */
1683 /* g_object_unref (G_OBJECT (iter)); */
1684 /* g_source_remove (timeout); */
1686 /* if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED && */
1687 /* priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED && */
1688 /* new_headers_array->len > 0) { */
1689 /* gint msg_num = 0; */
1691 /* /\* Order by date *\/ */
1692 /* g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date); */
1694 /* /\* TODO: Ask the user, instead of just failing, */
1695 /* * showing mail_nc_msg_count_limit_exceeded, with 'Get */
1696 /* * all' and 'Newest only' buttons. *\/ */
1697 /* if (new_headers_array->len > info->retrieve_limit) { */
1701 /* /\* Should be get only the headers or the message as well? *\/ */
1702 /* if (g_ascii_strcasecmp (info->retrieve_type, */
1703 /* MODEST_ACCOUNT_RETRIEVE_VALUE_HEADERS_ONLY) != 0) { */
1704 /* priv->done = 0; */
1705 /* priv->total = MIN (new_headers_array->len, info->retrieve_limit); */
1706 /* while (msg_num < priv->total) { */
1708 /* TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num)); */
1709 /* TnyFolder *folder = tny_header_get_folder (header); */
1710 /* TnyMsg *msg = tny_folder_get_msg (folder, header, NULL); */
1711 /* ModestMailOperationState *state; */
1712 /* ModestPair* pair; */
1715 /* /\* We can not just use the mail operation because the */
1716 /* values of done and total could change before the */
1717 /* idle is called *\/ */
1718 /* state = modest_mail_operation_clone_state (info->mail_op); */
1719 /* pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE); */
1720 /* g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once, */
1721 /* pair, (GDestroyNotify) modest_pair_free); */
1723 /* g_object_unref (msg); */
1724 /* g_object_unref (folder); */
1731 /* if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED) */
1734 /* /\* Copy the headers to a list and free the array *\/ */
1735 /* new_headers = tny_simple_list_new (); */
1736 /* for (i=0; i < new_headers_array->len; i++) { */
1737 /* TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i)); */
1738 /* tny_list_append (new_headers, G_OBJECT (header)); */
1740 /* g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL); */
1741 /* g_ptr_array_free (new_headers_array, FALSE); */
1744 /* /\* Perform send (if operation was not cancelled) *\/ */
1745 /* priv->done = 0; */
1746 /* priv->total = 0; */
1747 /* if (priv->account != NULL) */
1748 /* g_object_unref (priv->account); */
1750 /* if (info->transport_account) { */
1751 /* priv->account = g_object_ref (info->transport_account); */
1753 /* send_queue = modest_runtime_get_send_queue (info->transport_account); */
1754 /* if (send_queue) { */
1755 /* modest_tny_send_queue_try_to_send (send_queue); */
1757 /* g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR, */
1758 /* MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED, */
1759 /* "cannot create a send queue for %s\n", */
1760 /* tny_account_get_name (TNY_ACCOUNT (info->transport_account))); */
1761 /* priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED; */
1765 /* /\* Check if the operation was a success *\/ */
1766 /* if (!priv->error) { */
1767 /* priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS; */
1769 /* /\* Update the last updated key *\/ */
1770 /* g_idle_add_full (G_PRIORITY_HIGH_IDLE, */
1771 /* set_last_updated_idle, */
1772 /* g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))), */
1773 /* (GDestroyNotify) g_free); */
1777 /* /\* Set the account back to not busy *\/ */
1778 /* modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(), */
1779 /* info->account_name, FALSE); */
1781 /* if (info->callback) { */
1782 /* UpdateAccountInfo *idle_info; */
1784 /* /\* This thread is not in the main lock *\/ */
1785 /* idle_info = g_malloc0 (sizeof (UpdateAccountInfo)); */
1786 /* idle_info->mail_op = g_object_ref (info->mail_op); */
1787 /* idle_info->new_headers = (new_headers) ? g_object_ref (new_headers) : NULL; */
1788 /* idle_info->callback = info->callback; */
1789 /* idle_info->user_data = info->user_data; */
1790 /* g_idle_add (idle_update_account_cb, idle_info); */
1793 /* /\* Notify about operation end. Note that the info could be */
1794 /* freed before this idle happens, but the mail operation will */
1795 /* be still alive *\/ */
1796 /* g_idle_add (idle_notify_queue, g_object_ref (info->mail_op)); */
1799 /* if (new_headers) */
1800 /* g_object_unref (new_headers); */
1801 /* if (all_folders) */
1802 /* g_object_unref (all_folders); */
1803 /* g_object_unref (info->account); */
1804 /* if (info->transport_account) */
1805 /* g_object_unref (info->transport_account); */
1806 /* g_free (info->account_name); */
1807 /* g_free (info->retrieve_type); */
1808 /* g_slice_free (UpdateAccountInfo, info); */
1810 /* first_time = FALSE; */
1816 /* modest_mail_operation_update_account (ModestMailOperation *self, */
1817 /* const gchar *account_name, */
1818 /* UpdateAccountCallback callback, */
1819 /* gpointer user_data) */
1821 /* GThread *thread = NULL; */
1822 /* UpdateAccountInfo *info = NULL; */
1823 /* ModestMailOperationPrivate *priv = NULL; */
1824 /* ModestAccountMgr *mgr = NULL; */
1825 /* TnyStoreAccount *store_account = NULL; */
1826 /* TnyTransportAccount *transport_account = NULL; */
1828 /* g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE); */
1829 /* g_return_val_if_fail (account_name, FALSE); */
1831 /* /\* Init mail operation. Set total and done to 0, and do not */
1832 /* update them, this way the progress objects will know that */
1833 /* we have no clue about the number of the objects *\/ */
1834 /* priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self); */
1835 /* priv->total = 0; */
1836 /* priv->done = 0; */
1837 /* priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS; */
1838 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE; */
1840 /* /\* Get the store account *\/ */
1841 /* store_account = (TnyStoreAccount *) */
1842 /* modest_tny_account_store_get_server_account (modest_runtime_get_account_store (), */
1844 /* TNY_ACCOUNT_TYPE_STORE); */
1846 /* if (!store_account) { */
1847 /* g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR, */
1848 /* MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND, */
1849 /* "cannot get tny store account for %s\n", account_name); */
1853 /* priv->account = g_object_ref (store_account); */
1855 /* /\* Get the transport account, we can not do it in the thread */
1856 /* due to some problems with dbus *\/ */
1857 /* transport_account = (TnyTransportAccount *) */
1858 /* modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(), */
1859 /* account_name); */
1860 /* if (!transport_account) { */
1861 /* g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR, */
1862 /* MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND, */
1863 /* "cannot get tny transport account for %s\n", account_name); */
1867 /* /\* Create the helper object *\/ */
1868 /* info = g_slice_new (UpdateAccountInfo); */
1869 /* info->mail_op = self; */
1870 /* info->account = store_account; */
1871 /* info->transport_account = transport_account; */
1872 /* info->callback = callback; */
1873 /* info->account_name = g_strdup (account_name); */
1874 /* info->user_data = user_data; */
1876 /* /\* Get the message size limit *\/ */
1877 /* info->max_size = modest_conf_get_int (modest_runtime_get_conf (), */
1878 /* MODEST_CONF_MSG_SIZE_LIMIT, NULL); */
1879 /* if (info->max_size == 0) */
1880 /* info->max_size = G_MAXINT; */
1882 /* info->max_size = info->max_size * KB; */
1884 /* /\* Get per-account retrieval type *\/ */
1885 /* mgr = modest_runtime_get_account_mgr (); */
1886 /* info->retrieve_type = modest_account_mgr_get_retrieve_type (mgr, account_name); */
1888 /* /\* Get per-account message amount retrieval limit *\/ */
1889 /* info->retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, account_name); */
1890 /* if (info->retrieve_limit == 0) */
1891 /* info->retrieve_limit = G_MAXINT; */
1893 /* /\* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); *\/ */
1895 /* /\* Set account busy *\/ */
1896 /* modest_account_mgr_set_account_busy(mgr, account_name, TRUE); */
1898 /* modest_mail_operation_notify_start (self); */
1899 /* thread = g_thread_create (update_account_thread, info, FALSE, NULL); */
1904 /* if (store_account) */
1905 /* g_object_unref (store_account); */
1906 /* if (transport_account) */
1907 /* g_object_unref (transport_account); */
1908 /* priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED; */
1909 /* if (callback) { */
1910 /* callback (self, NULL, user_data); */
1912 /* modest_mail_operation_notify_end (self); */
1916 /* ******************************************************************* */
1917 /* ************************** STORE ACTIONS ************************* */
1918 /* ******************************************************************* */
1922 modest_mail_operation_create_folder (ModestMailOperation *self,
1923 TnyFolderStore *parent,
1926 ModestMailOperationPrivate *priv;
1927 TnyFolder *new_folder = NULL;
1929 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1930 g_return_val_if_fail (name, NULL);
1932 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1933 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1934 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1935 g_object_ref (parent) :
1936 modest_tny_folder_get_account (TNY_FOLDER (parent));
1938 /* Check for already existing folder */
1939 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1940 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1941 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1942 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1943 _CS("ckdg_ib_folder_already_exists"));
1947 if (TNY_IS_FOLDER (parent)) {
1948 /* Check folder rules */
1949 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1950 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1951 /* Set status failed and set an error */
1952 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1953 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1954 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1955 _("mail_in_ui_folder_create_error"));
1959 if (!strcmp (name, " ") || strchr (name, '/')) {
1960 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1961 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1962 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1963 _("mail_in_ui_folder_create_error"));
1967 /* Create the folder */
1968 modest_mail_operation_notify_start (self);
1969 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1970 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1972 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1975 /* Notify about operation end */
1976 modest_mail_operation_notify_end (self);
1982 modest_mail_operation_remove_folder (ModestMailOperation *self,
1984 gboolean remove_to_trash)
1986 TnyAccount *account;
1987 ModestMailOperationPrivate *priv;
1988 ModestTnyFolderRules rules;
1990 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1991 g_return_if_fail (TNY_IS_FOLDER (folder));
1993 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1995 /* Check folder rules */
1996 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1997 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1998 /* Set status failed and set an error */
1999 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2000 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2001 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2002 _("mail_in_ui_folder_delete_error"));
2006 /* Get the account */
2007 account = modest_tny_folder_get_account (folder);
2008 priv->account = g_object_ref(account);
2009 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2011 /* Delete folder or move to trash */
2012 if (remove_to_trash) {
2013 TnyFolder *trash_folder = NULL;
2014 trash_folder = modest_tny_account_get_special_folder (account,
2015 TNY_FOLDER_TYPE_TRASH);
2016 /* TODO: error_handling */
2018 modest_mail_operation_notify_start (self);
2019 modest_mail_operation_xfer_folder (self, folder,
2020 TNY_FOLDER_STORE (trash_folder),
2022 g_object_unref (trash_folder);
2025 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2027 modest_mail_operation_notify_start (self);
2028 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2029 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2032 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2034 g_object_unref (parent);
2036 g_warning ("%s: could not get parent folder", __FUNCTION__);
2038 g_object_unref (G_OBJECT (account));
2041 /* Notify about operation end */
2042 modest_mail_operation_notify_end (self);
2046 transfer_folder_status_cb (GObject *obj,
2050 ModestMailOperation *self;
2051 ModestMailOperationPrivate *priv;
2052 ModestMailOperationState *state;
2053 XFerMsgAsyncHelper *helper;
2055 g_return_if_fail (status != NULL);
2056 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
2058 helper = (XFerMsgAsyncHelper *) user_data;
2059 g_return_if_fail (helper != NULL);
2061 self = helper->mail_op;
2062 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2064 priv->done = status->position;
2065 priv->total = status->of_total;
2067 state = modest_mail_operation_clone_state (self);
2069 /* This is not a GDK lock because we are a Tinymail callback
2070 * which is already GDK locked by Tinymail */
2072 /* no gdk_threads_enter (), CHECKED */
2074 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2076 /* no gdk_threads_leave (), CHECKED */
2078 g_slice_free (ModestMailOperationState, state);
2083 transfer_folder_cb (TnyFolder *folder,
2085 TnyFolderStore *into,
2086 TnyFolder *new_folder,
2090 XFerMsgAsyncHelper *helper;
2091 ModestMailOperation *self = NULL;
2092 ModestMailOperationPrivate *priv = NULL;
2094 helper = (XFerMsgAsyncHelper *) user_data;
2095 g_return_if_fail (helper != NULL);
2097 self = helper->mail_op;
2098 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2101 priv->error = g_error_copy (err);
2103 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2104 } else if (cancelled) {
2105 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2106 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2107 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2108 _("Transference of %s was cancelled."),
2109 tny_folder_get_name (folder));
2112 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2115 /* Notify about operation end */
2116 modest_mail_operation_notify_end (self);
2118 /* If user defined callback function was defined, call it */
2119 if (helper->user_callback) {
2121 /* This is not a GDK lock because we are a Tinymail callback
2122 * which is already GDK locked by Tinymail */
2124 /* no gdk_threads_enter (), CHECKED */
2125 helper->user_callback (self, helper->user_data);
2126 /* no gdk_threads_leave () , CHECKED */
2130 g_object_unref (helper->mail_op);
2131 g_slice_free (XFerMsgAsyncHelper, helper);
2136 * This function checks if the new name is a valid name for our local
2137 * folders account. The new name could not be the same than then name
2138 * of any of the mandatory local folders
2140 * We can not rely on tinymail because tinymail does not check the
2141 * name of the virtual folders that the account could have in the case
2142 * that we're doing a rename (because it directly calls Camel which
2143 * knows nothing about our virtual folders).
2145 * In the case of an actual copy/move (i.e. move/copy a folder between
2146 * accounts) tinymail uses the tny_folder_store_create_account which
2147 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2148 * checks the new name of the folder, so this call in that case
2149 * wouldn't be needed. *But* NOTE that if tinymail changes its
2150 * implementation (if folder transfers within the same account is no
2151 * longer implemented as a rename) this call will allow Modest to work
2154 * If the new name is not valid, this function will set the status to
2155 * failed and will set also an error in the mail operation
2158 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2159 TnyFolderStore *into,
2160 const gchar *new_name)
2162 if (TNY_IS_ACCOUNT (into) &&
2163 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2164 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2166 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2167 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2168 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2169 _CS("ckdg_ib_folder_already_exists"));
2176 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2178 TnyFolderStore *parent,
2179 gboolean delete_original,
2180 XferAsyncUserCallback user_callback,
2183 ModestMailOperationPrivate *priv = NULL;
2184 ModestTnyFolderRules parent_rules = 0, rules;
2185 XFerMsgAsyncHelper *helper = NULL;
2186 const gchar *folder_name = NULL;
2187 const gchar *error_msg;
2189 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2190 g_return_if_fail (TNY_IS_FOLDER (folder));
2191 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2193 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2194 folder_name = tny_folder_get_name (folder);
2196 /* Set the error msg */
2197 error_msg = _("mail_in_ui_folder_move_target_error");
2199 /* Get account and set it into mail_operation */
2200 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2201 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2202 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2204 /* Get folder rules */
2205 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2206 if (TNY_IS_FOLDER (parent))
2207 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2209 /* Apply operation constraints */
2210 if ((gpointer) parent == (gpointer) folder ||
2211 (!TNY_IS_FOLDER_STORE (parent)) ||
2212 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2215 } else if (TNY_IS_FOLDER (parent) &&
2216 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2220 } else if (TNY_IS_FOLDER (parent) &&
2221 TNY_IS_FOLDER_STORE (folder) &&
2222 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2223 TNY_FOLDER_STORE (folder))) {
2224 /* Do not move a parent into a child */
2226 } else if (TNY_IS_FOLDER_STORE (parent) &&
2227 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2228 /* Check that the new folder name is not used by any
2231 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2232 /* Check that the new folder name is not used by any
2233 special local folder */
2236 /* Create the helper */
2237 helper = g_slice_new0 (XFerMsgAsyncHelper);
2238 helper->mail_op = g_object_ref (self);
2239 helper->dest_folder = NULL;
2240 helper->headers = NULL;
2241 helper->user_callback = user_callback;
2242 helper->user_data = user_data;
2244 /* Move/Copy folder */
2245 modest_mail_operation_notify_start (self);
2246 tny_folder_copy_async (folder,
2248 tny_folder_get_name (folder),
2251 transfer_folder_status_cb,
2257 /* Set status failed and set an error */
2258 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2259 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2260 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2263 /* Call the user callback if exists */
2265 user_callback (self, user_data);
2267 /* Notify the queue */
2268 modest_mail_operation_notify_end (self);
2272 modest_mail_operation_rename_folder (ModestMailOperation *self,
2276 ModestMailOperationPrivate *priv;
2277 ModestTnyFolderRules rules;
2278 XFerMsgAsyncHelper *helper;
2280 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2281 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2282 g_return_if_fail (name);
2284 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2286 /* Get account and set it into mail_operation */
2287 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2288 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2290 /* Check folder rules */
2291 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2292 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2293 /* Set status failed and set an error */
2294 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2295 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2296 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2297 _("FIXME: unable to rename"));
2299 /* Notify about operation end */
2300 modest_mail_operation_notify_end (self);
2301 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2302 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2303 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2304 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2305 _("FIXME: unable to rename"));
2306 /* Notify about operation end */
2307 modest_mail_operation_notify_end (self);
2309 TnyFolderStore *into;
2311 into = tny_folder_get_folder_store (folder);
2313 /* Check that the new folder name is not used by any
2314 special local folder */
2315 if (new_name_valid_if_local_account (priv, into, name)) {
2316 /* Create the helper */
2317 helper = g_slice_new0 (XFerMsgAsyncHelper);
2318 helper->mail_op = g_object_ref(self);
2319 helper->dest_folder = NULL;
2320 helper->headers = NULL;
2321 helper->user_callback = NULL;
2322 helper->user_data = NULL;
2324 /* Rename. Camel handles folder subscription/unsubscription */
2325 modest_mail_operation_notify_start (self);
2326 tny_folder_copy_async (folder, into, name, TRUE,
2328 transfer_folder_status_cb,
2331 modest_mail_operation_notify_end (self);
2333 g_object_unref (into);
2337 /* ******************************************************************* */
2338 /* ************************** MSG ACTIONS ************************* */
2339 /* ******************************************************************* */
2342 modest_mail_operation_get_msg (ModestMailOperation *self,
2344 GetMsgAsyncUserCallback user_callback,
2347 GetMsgInfo *helper = NULL;
2349 ModestMailOperationPrivate *priv;
2351 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2352 g_return_if_fail (TNY_IS_HEADER (header));
2354 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2355 folder = tny_header_get_folder (header);
2357 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2361 /* Get account and set it into mail_operation */
2362 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2364 /* Check for cached messages */
2365 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2366 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2368 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2370 /* Create the helper */
2371 helper = g_slice_new0 (GetMsgInfo);
2372 helper->header = g_object_ref (header);
2373 helper->mail_op = g_object_ref (self);
2374 helper->user_callback = user_callback;
2375 helper->user_data = user_data;
2376 helper->destroy_notify = NULL;
2377 helper->last_total_bytes = 0;
2378 helper->sum_total_bytes = 0;
2379 helper->total_bytes = tny_header_get_message_size (header);
2381 modest_mail_operation_notify_start (self);
2382 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2384 g_object_unref (G_OBJECT (folder));
2388 get_msg_status_cb (GObject *obj,
2392 GetMsgInfo *helper = NULL;
2394 g_return_if_fail (status != NULL);
2395 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2397 helper = (GetMsgInfo *) user_data;
2398 g_return_if_fail (helper != NULL);
2400 /* Notify progress */
2401 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2402 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2406 get_msg_async_cb (TnyFolder *folder,
2412 GetMsgInfo *info = NULL;
2413 ModestMailOperationPrivate *priv = NULL;
2416 info = (GetMsgInfo *) user_data;
2418 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2420 finished = (priv->done == priv->total) ? TRUE : FALSE;
2423 if (canceled || err) {
2424 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2426 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2427 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2430 /* Set the success status before calling the user callback */
2431 if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2432 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2436 /* Call the user callback */
2437 if (info->user_callback)
2438 info->user_callback (info->mail_op, info->header, canceled,
2439 msg, err, info->user_data);
2441 /* Notify about operation end if this is the last callback */
2443 /* Free user data */
2444 if (info->destroy_notify)
2445 info->destroy_notify (info->user_data);
2447 /* Notify about operation end */
2448 modest_mail_operation_notify_end (info->mail_op);
2452 g_object_unref (info->header);
2453 g_object_unref (info->mail_op);
2454 g_slice_free (GetMsgInfo, info);
2458 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2459 TnyList *header_list,
2460 GetMsgAsyncUserCallback user_callback,
2462 GDestroyNotify notify)
2464 ModestMailOperationPrivate *priv = NULL;
2465 gboolean size_ok = TRUE;
2467 TnyIterator *iter = NULL;
2469 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2471 /* Init mail operation */
2472 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2473 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2474 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2476 priv->total = tny_list_get_length(header_list);
2478 /* Get account and set it into mail_operation */
2479 if (tny_list_get_length (header_list) >= 1) {
2480 iter = tny_list_create_iterator (header_list);
2481 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2483 TnyFolder *folder = tny_header_get_folder (header);
2485 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2486 g_object_unref (folder);
2488 g_object_unref (header);
2491 if (tny_list_get_length (header_list) == 1) {
2492 g_object_unref (iter);
2497 /* Get msg size limit */
2498 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2499 MODEST_CONF_MSG_SIZE_LIMIT,
2502 g_clear_error (&(priv->error));
2503 max_size = G_MAXINT;
2505 max_size = max_size * KB;
2508 /* Check message size limits. If there is only one message
2509 always retrieve it */
2511 while (!tny_iterator_is_done (iter) && size_ok) {
2512 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2514 if (tny_header_get_message_size (header) >= max_size)
2516 g_object_unref (header);
2519 tny_iterator_next (iter);
2521 g_object_unref (iter);
2525 const gint msg_list_size = compute_message_list_size (header_list);
2527 modest_mail_operation_notify_start (self);
2528 iter = tny_list_create_iterator (header_list);
2529 while (!tny_iterator_is_done (iter)) {
2530 GetMsgInfo *msg_info = NULL;
2531 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2532 TnyFolder *folder = tny_header_get_folder (header);
2534 /* Create the message info */
2535 msg_info = g_slice_new0 (GetMsgInfo);
2536 msg_info->mail_op = g_object_ref (self);
2537 msg_info->header = g_object_ref (header);
2538 msg_info->user_callback = user_callback;
2539 msg_info->user_data = user_data;
2540 msg_info->destroy_notify = notify;
2541 msg_info->last_total_bytes = 0;
2542 msg_info->sum_total_bytes = 0;
2543 msg_info->total_bytes = msg_list_size;
2545 /* The callback will call it per each header */
2546 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2548 /* Free and go on */
2549 g_object_unref (header);
2550 g_object_unref (folder);
2551 tny_iterator_next (iter);
2553 g_object_unref (iter);
2555 /* Set status failed and set an error */
2556 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2557 /* FIXME: the error msg is different for pop */
2558 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2559 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2560 _("emev_ni_ui_imap_msg_size_exceed_error"));
2561 /* Remove from queue and free resources */
2562 modest_mail_operation_notify_end (self);
2570 modest_mail_operation_remove_msg (ModestMailOperation *self,
2572 gboolean remove_to_trash /*ignored*/)
2575 ModestMailOperationPrivate *priv;
2577 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2578 g_return_if_fail (TNY_IS_HEADER (header));
2580 if (remove_to_trash)
2581 g_warning ("remove to trash is not implemented");
2583 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2584 folder = tny_header_get_folder (header);
2586 /* Get account and set it into mail_operation */
2587 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2588 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2589 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2591 /* remove message from folder */
2592 tny_folder_remove_msg (folder, header, &(priv->error));
2594 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2595 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2597 modest_mail_operation_notify_start (self);
2599 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2600 TNY_IS_CAMEL_POP_FOLDER (folder))
2601 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> dont expunge */
2603 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2609 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2611 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2614 g_object_unref (G_OBJECT (folder));
2616 /* Notify about operation end */
2617 modest_mail_operation_notify_end (self);
2621 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2623 gboolean remove_to_trash /*ignored*/)
2626 ModestMailOperationPrivate *priv;
2627 TnyIterator *iter = NULL;
2628 TnyHeader *header = NULL;
2629 TnyList *remove_headers = NULL;
2630 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2632 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2633 g_return_if_fail (TNY_IS_LIST (headers));
2635 if (remove_to_trash)
2636 g_warning ("remove to trash is not implemented");
2638 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2640 remove_headers = g_object_ref(headers);
2642 /* Get folder from first header and sync it */
2643 iter = tny_list_create_iterator (headers);
2644 header = TNY_HEADER (tny_iterator_get_current (iter));
2645 folder = tny_header_get_folder (header);
2647 /* Don't remove messages that are being sent */
2648 if (modest_tny_folder_is_local_folder (folder)) {
2649 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2651 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2652 TnyTransportAccount *traccount = NULL;
2653 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2654 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2656 ModestTnySendQueueStatus status;
2657 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2658 TnyIterator *iter = tny_list_create_iterator(headers);
2659 g_object_unref(remove_headers);
2660 remove_headers = TNY_LIST(tny_simple_list_new());
2661 while (!tny_iterator_is_done(iter)) {
2663 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2664 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2665 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2666 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2667 tny_list_append(remove_headers, G_OBJECT(hdr));
2669 g_object_unref(hdr);
2671 tny_iterator_next(iter);
2673 g_object_unref(iter);
2674 g_object_unref(traccount);
2678 /* Get account and set it into mail_operation */
2679 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2680 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2681 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2683 /* remove message from folder */
2684 modest_mail_operation_notify_start (self);
2686 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2688 if (TNY_IS_CAMEL_IMAP_FOLDER (folder) ||
2689 TNY_IS_CAMEL_POP_FOLDER (folder))
2690 tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /* FALSE --> don't expunge */
2693 tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /* TRUE --> expunge */
2699 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2701 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2704 g_object_unref (remove_headers);
2705 g_object_unref (header);
2706 g_object_unref (iter);
2707 g_object_unref (G_OBJECT (folder));
2709 /* Notify about operation end */
2710 modest_mail_operation_notify_end (self);
2714 notify_progress_of_multiple_messages (ModestMailOperation *self,
2716 gint *last_total_bytes,
2717 gint *sum_total_bytes,
2719 gboolean increment_done)
2721 ModestMailOperationPrivate *priv;
2722 ModestMailOperationState *state;
2723 gboolean is_num_bytes;
2725 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2727 /* We know that tinymail sends us information about
2728 transferred bytes with this particular message */
2729 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2731 state = modest_mail_operation_clone_state (self);
2732 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2733 /* We know that we're in a different message when the
2734 total number of bytes to transfer is different. Of
2735 course it could fail if we're transferring messages
2736 of the same size, but this is a workarround */
2737 if (status->of_total != *last_total_bytes) {
2738 /* We need to increment the done when there is
2739 no information about each individual
2740 message, we need to do this in message
2741 transfers, and we don't do it for getting
2745 *sum_total_bytes += *last_total_bytes;
2746 *last_total_bytes = status->of_total;
2748 state->bytes_done += status->position + *sum_total_bytes;
2749 state->bytes_total = total_bytes;
2751 /* Notify the status change. Only notify about changes
2752 referred to bytes */
2753 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2757 g_slice_free (ModestMailOperationState, state);
2761 transfer_msgs_status_cb (GObject *obj,
2765 XFerMsgAsyncHelper *helper;
2767 g_return_if_fail (status != NULL);
2768 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2770 helper = (XFerMsgAsyncHelper *) user_data;
2771 g_return_if_fail (helper != NULL);
2773 /* Notify progress */
2774 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2775 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2780 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2782 XFerMsgAsyncHelper *helper;
2783 ModestMailOperation *self;
2784 ModestMailOperationPrivate *priv;
2785 TnyIterator *iter = NULL;
2786 TnyHeader *header = NULL;
2788 helper = (XFerMsgAsyncHelper *) user_data;
2789 self = helper->mail_op;
2791 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2794 priv->error = g_error_copy (err);
2796 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2797 } else if (cancelled) {
2798 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2799 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2800 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2801 _("Error trying to refresh the contents of %s"),
2802 tny_folder_get_name (folder));
2805 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2807 /* Update folder counts */
2808 tny_folder_poke_status (folder);
2809 tny_folder_poke_status (helper->dest_folder);
2813 /* Mark headers as deleted and seen */
2814 if ((helper->delete) &&
2815 (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
2816 iter = tny_list_create_iterator (helper->headers);
2817 while (!tny_iterator_is_done (iter)) {
2818 header = TNY_HEADER (tny_iterator_get_current (iter));
2819 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2820 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2821 g_object_unref (header);
2823 tny_iterator_next (iter);
2829 /* Notify about operation end */
2830 modest_mail_operation_notify_end (self);
2832 /* If user defined callback function was defined, call it */
2833 if (helper->user_callback) {
2834 /* This is not a GDK lock because we are a Tinymail callback and
2835 * Tinymail already acquires the Gdk lock */
2837 /* no gdk_threads_enter (), CHECKED */
2838 helper->user_callback (self, helper->user_data);
2839 /* no gdk_threads_leave (), CHECKED */
2843 if (helper->headers)
2844 g_object_unref (helper->headers);
2845 if (helper->dest_folder)
2846 g_object_unref (helper->dest_folder);
2847 if (helper->mail_op)
2848 g_object_unref (helper->mail_op);
2850 g_object_unref (folder);
2852 g_object_unref (iter);
2853 g_slice_free (XFerMsgAsyncHelper, helper);
2857 compute_message_list_size (TnyList *headers)
2862 iter = tny_list_create_iterator (headers);
2863 while (!tny_iterator_is_done (iter)) {
2864 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2865 size += tny_header_get_message_size (header);
2866 g_object_unref (header);
2867 tny_iterator_next (iter);
2869 g_object_unref (iter);
2875 compute_message_array_size (GPtrArray *headers)
2880 for (i = 0; i < headers->len; i++) {
2881 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2882 size += tny_header_get_message_size (header);
2890 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2893 gboolean delete_original,
2894 XferAsyncUserCallback user_callback,
2897 ModestMailOperationPrivate *priv = NULL;
2898 TnyIterator *iter = NULL;
2899 TnyFolder *src_folder = NULL;
2900 XFerMsgAsyncHelper *helper = NULL;
2901 TnyHeader *header = NULL;
2902 ModestTnyFolderRules rules = 0;
2904 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2905 g_return_if_fail (headers && TNY_IS_LIST (headers));
2906 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2908 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2909 priv->total = tny_list_get_length (headers);
2911 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2912 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2914 /* Apply folder rules */
2915 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2916 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2917 /* Set status failed and set an error */
2918 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2919 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2920 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2921 _CS("ckct_ib_unable_to_paste_here"));
2922 /* Notify the queue */
2923 modest_mail_operation_notify_end (self);
2927 /* Get source folder */
2928 iter = tny_list_create_iterator (headers);
2929 header = TNY_HEADER (tny_iterator_get_current (iter));
2931 src_folder = tny_header_get_folder (header);
2932 g_object_unref (header);
2934 g_object_unref (iter);
2936 if (src_folder == NULL) {
2937 /* Notify the queue */
2938 modest_mail_operation_notify_end (self);
2940 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2945 /* Check folder source and destination */
2946 if (src_folder == folder) {
2947 /* Set status failed and set an error */
2948 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2949 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2950 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2951 _("mail_in_ui_folder_copy_target_error"));
2953 /* Notify the queue */
2954 modest_mail_operation_notify_end (self);
2957 g_object_unref (src_folder);
2961 /* Create the helper */
2962 helper = g_slice_new0 (XFerMsgAsyncHelper);
2963 helper->mail_op = g_object_ref(self);
2964 helper->dest_folder = g_object_ref(folder);
2965 helper->headers = g_object_ref(headers);
2966 helper->user_callback = user_callback;
2967 helper->user_data = user_data;
2968 helper->delete = delete_original;
2969 helper->last_total_bytes = 0;
2970 helper->sum_total_bytes = 0;
2971 helper->total_bytes = compute_message_list_size (headers);
2973 /* Get account and set it into mail_operation */
2974 priv->account = modest_tny_folder_get_account (src_folder);
2976 /* Transfer messages */
2977 modest_mail_operation_notify_start (self);
2978 tny_folder_transfer_msgs_async (src_folder,
2983 transfer_msgs_status_cb,
2989 on_refresh_folder (TnyFolder *folder,
2994 RefreshAsyncHelper *helper = NULL;
2995 ModestMailOperation *self = NULL;
2996 ModestMailOperationPrivate *priv = NULL;
2998 helper = (RefreshAsyncHelper *) user_data;
2999 self = helper->mail_op;
3000 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3002 g_return_if_fail(priv!=NULL);
3005 priv->error = g_error_copy (error);
3006 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3011 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3012 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3013 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3014 _("Error trying to refresh the contents of %s"),
3015 tny_folder_get_name (folder));
3019 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3022 /* Call user defined callback, if it exists */
3023 if (helper->user_callback) {
3025 /* This is not a GDK lock because we are a Tinymail callback and
3026 * Tinymail already acquires the Gdk lock */
3027 helper->user_callback (self, folder, helper->user_data);
3031 g_slice_free (RefreshAsyncHelper, helper);
3033 /* Notify about operation end */
3034 modest_mail_operation_notify_end (self);
3035 g_object_unref(self);
3039 on_refresh_folder_status_update (GObject *obj,
3043 RefreshAsyncHelper *helper = NULL;
3044 ModestMailOperation *self = NULL;
3045 ModestMailOperationPrivate *priv = NULL;
3046 ModestMailOperationState *state;
3048 g_return_if_fail (user_data != NULL);
3049 g_return_if_fail (status != NULL);
3050 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
3052 helper = (RefreshAsyncHelper *) user_data;
3053 self = helper->mail_op;
3054 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3056 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3058 priv->done = status->position;
3059 priv->total = status->of_total;
3061 state = modest_mail_operation_clone_state (self);
3063 /* This is not a GDK lock because we are a Tinymail callback and
3064 * Tinymail already acquires the Gdk lock */
3065 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3067 g_slice_free (ModestMailOperationState, state);
3071 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3073 RefreshAsyncUserCallback user_callback,
3076 ModestMailOperationPrivate *priv = NULL;
3077 RefreshAsyncHelper *helper = NULL;
3079 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3081 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3083 /* Get account and set it into mail_operation */
3084 priv->account = modest_tny_folder_get_account (folder);
3085 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3087 /* Create the helper */
3088 helper = g_slice_new0 (RefreshAsyncHelper);
3089 helper->mail_op = g_object_ref(self);
3090 helper->user_callback = user_callback;
3091 helper->user_data = user_data;
3093 /* Refresh the folder. TODO: tinymail could issue a status
3094 updates before the callback call then this could happen. We
3095 must review the design */
3096 modest_mail_operation_notify_start (self);
3097 tny_folder_refresh_async (folder,
3099 on_refresh_folder_status_update,
3105 modest_mail_operation_notify_start (ModestMailOperation *self)
3107 ModestMailOperationPrivate *priv = NULL;
3109 g_return_if_fail (self);
3111 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3113 /* Ensure that all the fields are filled correctly */
3114 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3116 /* Notify the observers about the mail operation. We do not
3117 wrapp this emission because we assume that this function is
3118 always called from within the main lock */
3119 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3124 * It's used by the mail operation queue to notify the observers
3125 * attached to that signal that the operation finished. We need to use
3126 * that because tinymail does not give us the progress of a given
3127 * operation when it finishes (it directly calls the operation
3131 modest_mail_operation_notify_end (ModestMailOperation *self)
3133 ModestMailOperationPrivate *priv = NULL;
3135 g_return_if_fail (self);
3137 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3139 /* Notify the observers about the mail operation end. We do
3140 not wrapp this emission because we assume that this
3141 function is always called from within the main lock */
3142 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3144 /* Remove the error user data */
3145 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3146 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3150 modest_mail_operation_get_account (ModestMailOperation *self)
3152 ModestMailOperationPrivate *priv = NULL;
3154 g_return_val_if_fail (self, NULL);
3156 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3158 return (priv->account) ? g_object_ref (priv->account) : NULL;
3162 modest_mail_operation_noop (ModestMailOperation *self)
3164 ModestMailOperationPrivate *priv = NULL;
3166 g_return_if_fail (self);
3168 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3169 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3170 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3174 /* This mail operation does nothing actually */
3175 modest_mail_operation_notify_start (self);
3176 modest_mail_operation_notify_end (self);