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-tny-account.h>
49 #include <modest-tny-send-queue.h>
50 #include <modest-runtime.h>
51 #include "modest-text-utils.h"
52 #include "modest-tny-msg.h"
53 #include "modest-tny-folder.h"
54 #include "modest-tny-account-store.h"
55 #include "modest-tny-platform-factory.h"
56 #include "modest-marshal.h"
57 #include "modest-error.h"
58 #include "modest-mail-operation.h"
63 * Remove all these #ifdef stuff when the tinymail's idle calls become
66 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
68 /* 'private'/'protected' functions */
69 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
70 static void modest_mail_operation_init (ModestMailOperation *obj);
71 static void modest_mail_operation_finalize (GObject *obj);
73 static void get_msg_cb (TnyFolder *folder,
79 static void get_msg_status_cb (GObject *obj,
83 static void modest_mail_operation_notify_end (ModestMailOperation *self);
85 enum _ModestMailOperationSignals
87 PROGRESS_CHANGED_SIGNAL,
92 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
93 struct _ModestMailOperationPrivate {
100 ErrorCheckingUserCallback error_checking;
101 gpointer error_checking_user_data;
102 ModestMailOperationStatus status;
103 ModestMailOperationTypeOperation op_type;
106 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
107 MODEST_TYPE_MAIL_OPERATION, \
108 ModestMailOperationPrivate))
110 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
111 priv->status = new_status;\
114 typedef struct _GetMsgAsyncHelper {
115 ModestMailOperation *mail_op;
117 GetMsgAsyncUserCallback user_callback;
121 typedef struct _RefreshAsyncHelper {
122 ModestMailOperation *mail_op;
123 RefreshAsyncUserCallback user_callback;
125 } RefreshAsyncHelper;
127 typedef struct _XFerMsgAsyncHelper
129 ModestMailOperation *mail_op;
131 TnyFolder *dest_folder;
132 XferMsgsAsynUserCallback user_callback;
134 } XFerMsgAsyncHelper;
136 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
140 static void modest_mail_operation_create_msg (ModestMailOperation *self,
141 const gchar *from, const gchar *to,
142 const gchar *cc, const gchar *bcc,
143 const gchar *subject, const gchar *plain_body,
144 const gchar *html_body, const GList *attachments_list,
145 TnyHeaderFlags priority_flags,
146 ModestMailOperationCreateMsgCallback callback,
149 static gboolean idle_notify_queue (gpointer data);
152 ModestMailOperation *mail_op;
160 GList *attachments_list;
161 TnyHeaderFlags priority_flags;
162 ModestMailOperationCreateMsgCallback callback;
168 ModestMailOperation *mail_op;
170 ModestMailOperationCreateMsgCallback callback;
175 static GObjectClass *parent_class = NULL;
177 static guint signals[NUM_SIGNALS] = {0};
180 modest_mail_operation_get_type (void)
182 static GType my_type = 0;
184 static const GTypeInfo my_info = {
185 sizeof(ModestMailOperationClass),
186 NULL, /* base init */
187 NULL, /* base finalize */
188 (GClassInitFunc) modest_mail_operation_class_init,
189 NULL, /* class finalize */
190 NULL, /* class data */
191 sizeof(ModestMailOperation),
193 (GInstanceInitFunc) modest_mail_operation_init,
196 my_type = g_type_register_static (G_TYPE_OBJECT,
197 "ModestMailOperation",
204 modest_mail_operation_class_init (ModestMailOperationClass *klass)
206 GObjectClass *gobject_class;
207 gobject_class = (GObjectClass*) klass;
209 parent_class = g_type_class_peek_parent (klass);
210 gobject_class->finalize = modest_mail_operation_finalize;
212 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
215 * ModestMailOperation::progress-changed
216 * @self: the #MailOperation that emits the signal
217 * @user_data: user data set when the signal handler was connected
219 * Emitted when the progress of a mail operation changes
221 signals[PROGRESS_CHANGED_SIGNAL] =
222 g_signal_new ("progress-changed",
223 G_TYPE_FROM_CLASS (gobject_class),
225 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
227 g_cclosure_marshal_VOID__POINTER,
228 G_TYPE_NONE, 1, G_TYPE_POINTER);
233 modest_mail_operation_init (ModestMailOperation *obj)
235 ModestMailOperationPrivate *priv;
237 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
239 priv->account = NULL;
240 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
241 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
246 priv->error_checking = NULL;
247 priv->error_checking_user_data = NULL;
251 modest_mail_operation_finalize (GObject *obj)
253 ModestMailOperationPrivate *priv;
255 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
260 g_error_free (priv->error);
264 g_object_unref (priv->source);
268 g_object_unref (priv->account);
269 priv->account = NULL;
273 G_OBJECT_CLASS(parent_class)->finalize (obj);
277 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
280 ModestMailOperation *obj;
281 ModestMailOperationPrivate *priv;
283 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
284 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
286 priv->op_type = op_type;
288 priv->source = g_object_ref(source);
294 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
296 ErrorCheckingUserCallback error_handler,
299 ModestMailOperation *obj;
300 ModestMailOperationPrivate *priv;
302 obj = modest_mail_operation_new (op_type, source);
303 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
305 g_return_val_if_fail (error_handler != NULL, obj);
306 priv->error_checking = error_handler;
312 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
314 ModestMailOperationPrivate *priv;
316 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
317 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
319 if (priv->error_checking != NULL)
320 priv->error_checking (self, priv->error_checking_user_data);
324 ModestMailOperationTypeOperation
325 modest_mail_operation_get_type_operation (ModestMailOperation *self)
327 ModestMailOperationPrivate *priv;
329 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
331 return priv->op_type;
335 modest_mail_operation_is_mine (ModestMailOperation *self,
338 ModestMailOperationPrivate *priv;
340 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
341 if (priv->source == NULL) return FALSE;
343 return priv->source == me;
347 modest_mail_operation_get_source (ModestMailOperation *self)
349 ModestMailOperationPrivate *priv;
351 g_return_val_if_fail (self, NULL);
353 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
355 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
359 return g_object_ref (priv->source);
362 ModestMailOperationStatus
363 modest_mail_operation_get_status (ModestMailOperation *self)
365 ModestMailOperationPrivate *priv;
367 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
368 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
369 MODEST_MAIL_OPERATION_STATUS_INVALID);
371 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
373 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
374 return MODEST_MAIL_OPERATION_STATUS_INVALID;
381 modest_mail_operation_get_error (ModestMailOperation *self)
383 ModestMailOperationPrivate *priv;
385 g_return_val_if_fail (self, NULL);
386 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
388 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
391 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
399 modest_mail_operation_cancel (ModestMailOperation *self)
401 ModestMailOperationPrivate *priv;
402 gboolean canceled = FALSE;
404 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
406 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
408 /* Note that if we call cancel with an already canceled mail
409 operation the progress changed signal won't be emitted */
410 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
414 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
416 /* Cancel the mail operation. We need to wrap it between this
417 start/stop operations to allow following calls to the
419 g_return_val_if_fail (priv->account, FALSE);
420 tny_account_cancel (priv->account);
426 modest_mail_operation_get_task_done (ModestMailOperation *self)
428 ModestMailOperationPrivate *priv;
430 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
432 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
437 modest_mail_operation_get_task_total (ModestMailOperation *self)
439 ModestMailOperationPrivate *priv;
441 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
443 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
448 modest_mail_operation_is_finished (ModestMailOperation *self)
450 ModestMailOperationPrivate *priv;
451 gboolean retval = FALSE;
453 if (!MODEST_IS_MAIL_OPERATION (self)) {
454 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
458 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
460 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
461 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
462 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
463 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
473 modest_mail_operation_get_id (ModestMailOperation *self)
475 ModestMailOperationPrivate *priv;
477 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
479 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
484 modest_mail_operation_set_id (ModestMailOperation *self,
487 ModestMailOperationPrivate *priv;
489 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
491 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
496 * Creates an image of the current state of a mail operation, the
497 * caller must free it
499 static ModestMailOperationState *
500 modest_mail_operation_clone_state (ModestMailOperation *self)
502 ModestMailOperationState *state;
503 ModestMailOperationPrivate *priv;
505 /* FIXME: this should be fixed properly
507 * in some cases, priv was NULL, so checking here to
510 g_return_val_if_fail (self, NULL);
511 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
512 g_return_val_if_fail (priv, NULL);
517 state = g_slice_new (ModestMailOperationState);
519 state->status = priv->status;
520 state->op_type = priv->op_type;
521 state->done = priv->done;
522 state->total = priv->total;
523 state->finished = modest_mail_operation_is_finished (self);
524 state->bytes_done = 0;
525 state->bytes_total = 0;
530 /* ******************************************************************* */
531 /* ************************** SEND ACTIONS ************************* */
532 /* ******************************************************************* */
535 modest_mail_operation_send_mail (ModestMailOperation *self,
536 TnyTransportAccount *transport_account,
539 TnySendQueue *send_queue = NULL;
540 ModestMailOperationPrivate *priv;
542 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
543 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
544 g_return_if_fail (TNY_IS_MSG (msg));
546 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
548 /* Get account and set it into mail_operation */
549 priv->account = g_object_ref (transport_account);
553 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
554 if (!TNY_IS_SEND_QUEUE(send_queue)) {
555 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
556 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
557 "modest: could not find send queue for account\n");
559 /* TODO: connect to the msg-sent in order to know when
560 the mail operation is finished */
561 tny_send_queue_add (send_queue, msg, &(priv->error));
562 /* TODO: we're setting always success, do the check in
564 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
567 /* TODO: do this in the handler of the "msg-sent"
568 signal.Notify about operation end */
569 modest_mail_operation_notify_end (self);
573 idle_create_msg_cb (gpointer idle_data)
575 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
577 gdk_threads_enter ();
578 info->callback (info->mail_op, info->msg, info->userdata);
579 gdk_threads_leave ();
580 g_object_unref (info->mail_op);
582 g_object_unref (info->msg);
583 g_slice_free (CreateMsgIdleInfo, info);
589 create_msg_thread (gpointer thread_data)
591 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
592 TnyMsg *new_msg = NULL;
593 ModestMailOperationPrivate *priv;
595 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
596 if (info->html_body == NULL) {
597 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
598 info->bcc, info->subject, info->plain_body,
599 info->attachments_list); /* FIXME: attachments */
601 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
602 info->bcc, info->subject, info->html_body,
603 info->plain_body, info->attachments_list);
608 /* Set priority flags in message */
609 header = tny_msg_get_header (new_msg);
610 if (info->priority_flags != 0)
611 tny_header_set_flags (header, info->priority_flags);
612 if (info->attachments_list != NULL) {
613 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
615 g_object_unref (G_OBJECT(header));
617 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
618 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
619 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
620 "modest: failed to create a new msg\n");
628 g_free (info->plain_body);
629 g_free (info->html_body);
630 g_free (info->subject);
631 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
632 g_list_free (info->attachments_list);
634 if (info->callback) {
635 CreateMsgIdleInfo *idle_info;
636 idle_info = g_slice_new0 (CreateMsgIdleInfo);
637 idle_info->mail_op = info->mail_op;
638 g_object_ref (info->mail_op);
639 idle_info->msg = new_msg;
641 g_object_ref (new_msg);
642 idle_info->callback = info->callback;
643 idle_info->userdata = info->userdata;
644 g_idle_add (idle_create_msg_cb, idle_info);
646 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
649 g_object_unref (info->mail_op);
650 g_slice_free (CreateMsgInfo, info);
655 modest_mail_operation_create_msg (ModestMailOperation *self,
656 const gchar *from, const gchar *to,
657 const gchar *cc, const gchar *bcc,
658 const gchar *subject, const gchar *plain_body,
659 const gchar *html_body,
660 const GList *attachments_list,
661 TnyHeaderFlags priority_flags,
662 ModestMailOperationCreateMsgCallback callback,
665 CreateMsgInfo *info = NULL;
667 info = g_slice_new0 (CreateMsgInfo);
668 info->mail_op = self;
671 info->from = g_strdup (from);
672 info->to = g_strdup (to);
673 info->cc = g_strdup (cc);
674 info->bcc = g_strdup (bcc);
675 info->subject = g_strdup (subject);
676 info->plain_body = g_strdup (plain_body);
677 info->html_body = g_strdup (html_body);
678 info->attachments_list = g_list_copy ((GList *) attachments_list);
679 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
680 info->priority_flags = priority_flags;
682 info->callback = callback;
683 info->userdata = userdata;
685 g_thread_create (create_msg_thread, info, FALSE, NULL);
690 TnyTransportAccount *transport_account;
695 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
699 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
700 TnyFolder *draft_folder = NULL;
701 TnyFolder *outbox_folder = NULL;
708 /* Call mail operation */
709 modest_mail_operation_send_mail (self, info->transport_account, msg);
711 /* Remove old mail from its source folder */
712 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
713 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_OUTBOX);
714 if (info->draft_msg != NULL) {
715 TnyFolder *folder = NULL;
716 TnyFolder *src_folder = NULL;
717 TnyFolderType folder_type;
718 folder = tny_msg_get_folder (info->draft_msg);
719 if (folder == NULL) goto end;
720 folder_type = modest_tny_folder_guess_folder_type (folder);
721 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
722 src_folder = outbox_folder;
724 src_folder = draft_folder;
726 /* Note: This can fail (with a warning) if the message is not really already in a folder,
727 * because this function requires it to have a UID. */
728 header = tny_msg_get_header (info->draft_msg);
729 tny_folder_remove_msg (src_folder, header, NULL);
730 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
731 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
732 g_object_unref (header);
733 g_object_unref (folder);
738 g_object_unref (info->draft_msg);
740 g_object_unref (draft_folder);
742 g_object_unref (outbox_folder);
743 if (info->transport_account)
744 g_object_unref (info->transport_account);
745 g_slice_free (SendNewMailInfo, info);
746 modest_mail_operation_notify_end (self);
750 modest_mail_operation_send_new_mail (ModestMailOperation *self,
751 TnyTransportAccount *transport_account,
753 const gchar *from, const gchar *to,
754 const gchar *cc, const gchar *bcc,
755 const gchar *subject, const gchar *plain_body,
756 const gchar *html_body,
757 const GList *attachments_list,
758 TnyHeaderFlags priority_flags)
760 ModestMailOperationPrivate *priv = NULL;
761 SendNewMailInfo *info;
763 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
764 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
766 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
768 /* Check parametters */
770 /* Set status failed and set an error */
771 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
772 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
773 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
774 _("Error trying to send a mail. You need to set at least one recipient"));
777 info = g_slice_new0 (SendNewMailInfo);
778 info->transport_account = transport_account;
779 if (transport_account)
780 g_object_ref (transport_account);
781 info->draft_msg = draft_msg;
783 g_object_ref (draft_msg);
784 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
785 attachments_list, priority_flags,
786 modest_mail_operation_send_new_mail_cb, info);
792 TnyTransportAccount *transport_account;
794 ModestMsgEditWindow *edit_window;
798 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
802 TnyFolder *src_folder = NULL;
803 TnyFolder *folder = NULL;
804 TnyHeader *header = NULL;
805 ModestMailOperationPrivate *priv = NULL;
806 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
808 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
810 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
811 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
812 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
813 "modest: failed to create a new msg\n");
817 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
819 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
820 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
821 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
822 "modest: failed to create a new msg\n");
827 tny_folder_add_msg (folder, msg, &(priv->error));
829 if ((!priv->error) && (info->draft_msg != NULL)) {
830 header = tny_msg_get_header (info->draft_msg);
831 src_folder = tny_header_get_folder (header);
832 /* Remove the old draft expunging it */
833 tny_folder_remove_msg (src_folder, header, NULL);
834 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
835 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
836 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */
837 g_object_unref (header);
841 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
843 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
845 if (info->edit_window)
846 modest_msg_edit_window_set_draft (info->edit_window, msg);
851 g_object_unref (G_OBJECT(folder));
853 g_object_unref (G_OBJECT(src_folder));
854 if (info->edit_window)
855 g_object_unref (G_OBJECT(info->edit_window));
857 g_object_unref (G_OBJECT (info->draft_msg));
858 if (info->transport_account)
859 g_object_unref (G_OBJECT(info->transport_account));
860 g_slice_free (SaveToDraftsInfo, info);
862 modest_mail_operation_notify_end (self);
866 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
867 TnyTransportAccount *transport_account,
869 ModestMsgEditWindow *edit_window,
870 const gchar *from, const gchar *to,
871 const gchar *cc, const gchar *bcc,
872 const gchar *subject, const gchar *plain_body,
873 const gchar *html_body,
874 const GList *attachments_list,
875 TnyHeaderFlags priority_flags)
877 ModestMailOperationPrivate *priv = NULL;
878 SaveToDraftsInfo *info = NULL;
880 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
881 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
883 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
885 /* Get account and set it into mail_operation */
886 priv->account = g_object_ref (transport_account);
888 info = g_slice_new0 (SaveToDraftsInfo);
889 info->transport_account = g_object_ref (transport_account);
890 info->draft_msg = draft_msg;
892 g_object_ref (draft_msg);
893 info->edit_window = edit_window;
895 g_object_ref (edit_window);
897 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
898 attachments_list, priority_flags,
899 modest_mail_operation_save_to_drafts_cb, info);
905 ModestMailOperation *mail_op;
906 TnyStoreAccount *account;
907 TnyTransportAccount *transport_account;
910 gchar *retrieve_type;
912 UpdateAccountCallback callback;
919 ModestMailOperation *mail_op;
920 TnyMimePart *mime_part;
922 GetMimePartSizeCallback callback;
924 } GetMimePartSizeInfo;
926 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
927 /* We use this folder observer to track the headers that have been
928 * added to a folder */
931 TnyList *new_headers;
932 } InternalFolderObserver;
936 } InternalFolderObserverClass;
938 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
940 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
941 internal_folder_observer,
943 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
947 foreach_add_item (gpointer header, gpointer user_data)
949 tny_list_prepend (TNY_LIST (user_data),
950 g_object_ref (G_OBJECT (header)));
953 /* This is the method that looks for new messages in a folder */
955 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
957 InternalFolderObserver *derived = (InternalFolderObserver *)self;
959 TnyFolderChangeChanged changed;
961 changed = tny_folder_change_get_changed (change);
963 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
966 /* Get added headers */
967 list = tny_simple_list_new ();
968 tny_folder_change_get_added_headers (change, list);
970 /* Add them to the folder observer */
971 tny_list_foreach (list, foreach_add_item,
972 derived->new_headers);
974 g_object_unref (G_OBJECT (list));
979 internal_folder_observer_init (InternalFolderObserver *self)
981 self->new_headers = tny_simple_list_new ();
984 internal_folder_observer_finalize (GObject *object)
986 InternalFolderObserver *self;
988 self = (InternalFolderObserver *) object;
989 g_object_unref (self->new_headers);
991 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
994 tny_folder_observer_init (TnyFolderObserverIface *iface)
996 iface->update_func = internal_folder_observer_update;
999 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1001 GObjectClass *object_class;
1003 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1004 object_class = (GObjectClass*) klass;
1005 object_class->finalize = internal_folder_observer_finalize;
1011 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
1014 TnyList *folders = tny_simple_list_new ();
1016 tny_folder_store_get_folders (store, folders, query, NULL);
1017 iter = tny_list_create_iterator (folders);
1019 while (!tny_iterator_is_done (iter)) {
1021 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1023 tny_list_prepend (all_folders, G_OBJECT (folder));
1024 recurse_folders (folder, query, all_folders);
1025 g_object_unref (G_OBJECT (folder));
1028 tny_iterator_next (iter);
1030 g_object_unref (G_OBJECT (iter));
1031 g_object_unref (G_OBJECT (folders));
1035 * Issues the "progress-changed" signal. The timer won't be removed,
1036 * so you must call g_source_remove to stop the signal emission
1039 idle_notify_progress (gpointer data)
1041 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1042 ModestMailOperationState *state;
1044 state = modest_mail_operation_clone_state (mail_op);
1045 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1046 gdk_threads_enter ();
1048 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1049 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1050 gdk_threads_leave ();
1052 g_slice_free (ModestMailOperationState, state);
1058 * Issues the "progress-changed" signal and removes the timer. It uses
1059 * a lock to ensure that the progress information of the mail
1060 * operation is not modified while there are notifications pending
1063 idle_notify_progress_once (gpointer data)
1067 pair = (ModestPair *) data;
1069 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1070 gdk_threads_enter ();
1072 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1073 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1074 gdk_threads_leave ();
1077 /* Free the state and the reference to the mail operation */
1078 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1079 g_object_unref (pair->first);
1085 * Used to notify the queue from the main
1086 * loop. We call it inside an idle call to achieve that
1089 idle_notify_queue (gpointer data)
1091 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1093 /* Do not need to block, the notify end will do it for us */
1094 modest_mail_operation_notify_end (mail_op);
1095 g_object_unref (mail_op);
1101 compare_headers_by_date (gconstpointer a,
1104 TnyHeader **header1, **header2;
1105 time_t sent1, sent2;
1107 header1 = (TnyHeader **) a;
1108 header2 = (TnyHeader **) b;
1110 sent1 = tny_header_get_date_sent (*header1);
1111 sent2 = tny_header_get_date_sent (*header2);
1113 /* We want the most recent ones (greater time_t) at the
1122 set_last_updated_idle (gpointer data)
1124 gdk_threads_enter ();
1126 /* It does not matter if the time is not exactly the same than
1127 the time when this idle was called, it's just an
1128 approximation and it won't be very different */
1129 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1131 MODEST_ACCOUNT_LAST_UPDATED,
1135 gdk_threads_leave ();
1141 idle_update_account_cb (gpointer data)
1143 UpdateAccountInfo *idle_info;
1145 idle_info = (UpdateAccountInfo *) data;
1147 gdk_threads_enter ();
1148 idle_info->callback (idle_info->mail_op,
1149 idle_info->new_headers,
1150 idle_info->user_data);
1151 gdk_threads_leave ();
1154 g_object_unref (idle_info->mail_op);
1162 update_account_thread (gpointer thr_user_data)
1164 static gboolean first_time = TRUE;
1165 UpdateAccountInfo *info = NULL;
1166 TnyList *all_folders = NULL;
1167 GPtrArray *new_headers = NULL;
1168 TnyIterator *iter = NULL;
1169 TnyFolderStoreQuery *query = NULL;
1170 ModestMailOperationPrivate *priv = NULL;
1171 ModestTnySendQueue *send_queue = NULL;
1172 gint num_new_headers = 0;
1174 info = (UpdateAccountInfo *) thr_user_data;
1175 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1177 /* Get account and set it into mail_operation */
1178 priv->account = g_object_ref (info->account);
1181 * Previousl, we did this for POP3, to do a logout-login upon send/receive,
1182 * because many POP-servers (like Gmail) do not
1183 * show any updates unless we do that.
1184 * But that didn't work with gmail anyway,
1185 * and tinymail now takes care of this itself by disconnecting
1186 * automatically after using the connection.
1189 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT (priv->account))
1190 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1193 /* Get all the folders. We can do it synchronously because
1194 we're already running in a different thread than the UI */
1195 all_folders = tny_simple_list_new ();
1196 query = tny_folder_store_query_new ();
1197 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1198 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1203 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1207 iter = tny_list_create_iterator (all_folders);
1208 while (!tny_iterator_is_done (iter)) {
1209 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1211 recurse_folders (folder, query, all_folders);
1212 g_object_unref (folder);
1214 tny_iterator_next (iter);
1216 g_object_unref (G_OBJECT (iter));
1218 /* Update status and notify. We need to call the notification
1219 with a source function in order to call it from the main
1220 loop. We need that in order not to get into trouble with
1221 Gtk+. We use a timeout in order to provide more status
1222 information, because the sync tinymail call does not
1223 provide it for the moment */
1224 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1226 /* Refresh folders */
1227 num_new_headers = 0;
1228 new_headers = g_ptr_array_new ();
1229 iter = tny_list_create_iterator (all_folders);
1231 while (!tny_iterator_is_done (iter) && !priv->error &&
1232 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1234 InternalFolderObserver *observer;
1235 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1237 /* Refresh the folder */
1238 /* Our observer receives notification of new emails during folder refreshes,
1239 * so we can use observer->new_headers.
1241 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1242 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1244 /* This gets the status information (headers) from the server.
1245 * We use the blocking version, because we are already in a separate
1249 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1250 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1253 /* If the retrieve type is full messages, refresh and get the messages */
1254 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1256 iter = tny_list_create_iterator (observer->new_headers);
1257 while (!tny_iterator_is_done (iter)) {
1258 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1260 /* Apply per-message size limits */
1261 if (tny_header_get_message_size (header) < info->max_size)
1262 g_ptr_array_add (new_headers, g_object_ref (header));
1264 g_object_unref (header);
1265 tny_iterator_next (iter);
1267 g_object_unref (iter);
1269 /* We do not need to do it the first time
1270 because it's automatically done by the tree
1272 if (G_UNLIKELY (!first_time))
1273 tny_folder_poke_status (TNY_FOLDER (folder));
1275 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1276 g_object_unref (observer);
1280 g_object_unref (G_OBJECT (folder));
1283 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1285 tny_iterator_next (iter);
1288 g_object_unref (G_OBJECT (iter));
1289 g_source_remove (timeout);
1291 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1292 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1293 new_headers->len > 0) {
1297 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1299 /* Apply message count limit */
1300 /* If the number of messages exceeds the maximum, ask the
1301 * user to download them all,
1302 * as per the UI spec "Retrieval Limits" section in 4.4:
1304 if (new_headers->len > info->retrieve_limit) {
1305 /* TODO: Ask the user, instead of just
1307 * mail_nc_msg_count_limit_exceeded, with 'Get
1308 * all' and 'Newest only' buttons. */
1309 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1310 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1311 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1312 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1313 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1318 priv->total = MIN (new_headers->len, info->retrieve_limit);
1319 while (msg_num < priv->total) {
1321 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1322 TnyFolder *folder = tny_header_get_folder (header);
1323 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1324 ModestMailOperationState *state;
1328 /* We can not just use the mail operation because the
1329 values of done and total could change before the
1331 state = modest_mail_operation_clone_state (info->mail_op);
1332 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1333 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1334 pair, (GDestroyNotify) modest_pair_free);
1336 g_object_unref (msg);
1337 g_object_unref (folder);
1343 /* Get the number of new headers and free them */
1344 num_new_headers = new_headers->len;
1345 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1346 g_ptr_array_free (new_headers, FALSE);
1348 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1351 /* Perform send (if operation was not cancelled) */
1352 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1355 if (priv->account != NULL)
1356 g_object_unref (priv->account);
1357 priv->account = g_object_ref (info->transport_account);
1359 send_queue = modest_runtime_get_send_queue (info->transport_account);
1361 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1362 modest_tny_send_queue_try_to_send (send_queue);
1363 /* g_source_remove (timeout); */
1365 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1366 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1367 "cannot create a send queue for %s\n",
1368 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1369 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1372 /* Check if the operation was a success */
1374 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1376 /* Update the last updated key */
1377 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1378 set_last_updated_idle,
1379 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1380 (GDestroyNotify) g_free);
1385 if (info->callback) {
1386 UpdateAccountInfo *idle_info;
1388 /* This thread is not in the main lock */
1389 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1390 idle_info->mail_op = g_object_ref (info->mail_op);
1391 idle_info->new_headers = num_new_headers;
1392 idle_info->callback = info->callback;
1393 g_idle_add (idle_update_account_cb, idle_info);
1396 /* Notify about operation end. Note that the info could be
1397 freed before this idle happens, but the mail operation will
1399 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1402 g_object_unref (query);
1403 g_object_unref (all_folders);
1404 g_object_unref (info->account);
1405 g_object_unref (info->transport_account);
1406 g_free (info->retrieve_type);
1407 g_slice_free (UpdateAccountInfo, info);
1415 modest_mail_operation_update_account (ModestMailOperation *self,
1416 const gchar *account_name,
1417 UpdateAccountCallback callback,
1420 GThread *thread = NULL;
1421 UpdateAccountInfo *info = NULL;
1422 ModestMailOperationPrivate *priv = NULL;
1423 ModestAccountMgr *mgr = NULL;
1424 TnyStoreAccount *store_account = NULL;
1425 TnyTransportAccount *transport_account = NULL;
1427 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1428 g_return_val_if_fail (account_name, FALSE);
1430 /* Init mail operation. Set total and done to 0, and do not
1431 update them, this way the progress objects will know that
1432 we have no clue about the number of the objects */
1433 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1436 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1438 /* Get the Modest account */
1439 store_account = (TnyStoreAccount *)
1440 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1442 TNY_ACCOUNT_TYPE_STORE);
1444 /* Make sure that we have a connection, and request one
1446 * TODO: Is there some way to trigger this for every attempt to
1447 * use the network? */
1448 if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
1451 if (!store_account) {
1452 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1453 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1454 "cannot get tny store account for %s\n", account_name);
1459 /* Get the transport account, we can not do it in the thread
1460 due to some problems with dbus */
1461 transport_account = (TnyTransportAccount *)
1462 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1464 if (!transport_account) {
1465 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1466 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1467 "cannot get tny transport account for %s\n", account_name);
1471 /* Create the helper object */
1472 info = g_slice_new (UpdateAccountInfo);
1473 info->mail_op = self;
1474 info->account = store_account;
1475 info->transport_account = transport_account;
1476 info->callback = callback;
1477 info->user_data = user_data;
1479 /* Get the message size limit */
1480 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1481 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1482 if (info->max_size == 0)
1483 info->max_size = G_MAXINT;
1485 info->max_size = info->max_size * KB;
1487 /* Get per-account retrieval type */
1488 mgr = modest_runtime_get_account_mgr ();
1489 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1490 MODEST_ACCOUNT_RETRIEVE, FALSE);
1492 /* Get per-account message amount retrieval limit */
1493 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1494 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1495 if (info->retrieve_limit == 0)
1496 info->retrieve_limit = G_MAXINT;
1498 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1500 /* Set account busy */
1501 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1502 priv->account_name = g_strdup(account_name);
1504 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1509 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1511 callback (self, 0, user_data);
1512 modest_mail_operation_notify_end (self);
1516 /* ******************************************************************* */
1517 /* ************************** STORE ACTIONS ************************* */
1518 /* ******************************************************************* */
1522 modest_mail_operation_create_folder (ModestMailOperation *self,
1523 TnyFolderStore *parent,
1526 ModestMailOperationPrivate *priv;
1527 TnyFolder *new_folder = NULL;
1529 TnyList *list = tny_simple_list_new ();
1530 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1532 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1533 g_return_val_if_fail (name, NULL);
1535 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1537 /* Check for already existing folder */
1538 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1539 tny_folder_store_get_folders (parent, list, query, NULL);
1540 g_object_unref (G_OBJECT (query));
1542 if (tny_list_get_length (list) > 0) {
1543 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1544 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1545 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1546 _CS("ckdg_ib_folder_already_exists"));
1549 g_object_unref (G_OBJECT (list));
1552 if (TNY_IS_FOLDER (parent)) {
1553 /* Check folder rules */
1554 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1555 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1556 /* Set status failed and set an error */
1557 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1558 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1559 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1560 _("mail_in_ui_folder_create_error"));
1564 if (!strcmp (name, " ") || strchr (name, '/')) {
1565 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1566 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1567 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1568 _("mail_in_ui_folder_create_error"));
1572 /* Create the folder */
1573 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1574 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1576 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1579 /* Notify about operation end */
1580 modest_mail_operation_notify_end (self);
1586 modest_mail_operation_remove_folder (ModestMailOperation *self,
1588 gboolean remove_to_trash)
1590 TnyAccount *account;
1591 ModestMailOperationPrivate *priv;
1592 ModestTnyFolderRules rules;
1594 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1595 g_return_if_fail (TNY_IS_FOLDER (folder));
1597 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1599 /* Check folder rules */
1600 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1601 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1602 /* Set status failed and set an error */
1603 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1604 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1605 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1606 _("mail_in_ui_folder_delete_error"));
1610 /* Get the account */
1611 account = modest_tny_folder_get_account (folder);
1612 priv->account = g_object_ref(account);
1614 /* Delete folder or move to trash */
1615 if (remove_to_trash) {
1616 TnyFolder *trash_folder = NULL;
1617 trash_folder = modest_tny_account_get_special_folder (account,
1618 TNY_FOLDER_TYPE_TRASH);
1619 /* TODO: error_handling */
1621 modest_mail_operation_xfer_folder (self, folder,
1622 TNY_FOLDER_STORE (trash_folder),
1624 g_object_unref (trash_folder);
1627 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1629 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1630 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1633 g_object_unref (G_OBJECT (parent));
1635 g_object_unref (G_OBJECT (account));
1638 /* Notify about operation end */
1639 modest_mail_operation_notify_end (self);
1643 transfer_folder_status_cb (GObject *obj,
1647 ModestMailOperation *self;
1648 ModestMailOperationPrivate *priv;
1649 ModestMailOperationState *state;
1650 XFerMsgAsyncHelper *helper;
1652 g_return_if_fail (status != NULL);
1653 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1655 helper = (XFerMsgAsyncHelper *) user_data;
1656 g_return_if_fail (helper != NULL);
1658 self = helper->mail_op;
1659 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1661 priv->done = status->position;
1662 priv->total = status->of_total;
1664 state = modest_mail_operation_clone_state (self);
1665 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1666 gdk_threads_enter ();
1668 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1669 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1670 gdk_threads_leave ();
1672 g_slice_free (ModestMailOperationState, state);
1677 transfer_folder_cb (TnyFolder *folder,
1678 TnyFolderStore *into,
1680 TnyFolder *new_folder,
1684 XFerMsgAsyncHelper *helper;
1685 ModestMailOperation *self = NULL;
1686 ModestMailOperationPrivate *priv = NULL;
1688 helper = (XFerMsgAsyncHelper *) user_data;
1689 g_return_if_fail (helper != NULL);
1691 self = helper->mail_op;
1692 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1695 priv->error = g_error_copy (*err);
1697 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1698 } else if (cancelled) {
1699 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1700 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1701 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1702 _("Transference of %s was cancelled."),
1703 tny_folder_get_name (folder));
1706 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1709 /* Notify about operation end */
1710 modest_mail_operation_notify_end (self);
1712 /* If user defined callback function was defined, call it */
1713 if (helper->user_callback) {
1714 gdk_threads_enter ();
1715 helper->user_callback (priv->source, helper->user_data);
1716 gdk_threads_leave ();
1720 g_object_unref (helper->mail_op);
1721 g_slice_free (XFerMsgAsyncHelper, helper);
1726 * This function checks if the new name is a valid name for our local
1727 * folders account. The new name could not be the same than then name
1728 * of any of the mandatory local folders
1730 * We can not rely on tinymail because tinymail does not check the
1731 * name of the virtual folders that the account could have in the case
1732 * that we're doing a rename (because it directly calls Camel which
1733 * knows nothing about our virtual folders).
1735 * In the case of an actual copy/move (i.e. move/copy a folder between
1736 * accounts) tinymail uses the tny_folder_store_create_account which
1737 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1738 * checks the new name of the folder, so this call in that case
1739 * wouldn't be needed. *But* NOTE that if tinymail changes its
1740 * implementation (if folder transfers within the same account is no
1741 * longer implemented as a rename) this call will allow Modest to work
1744 * If the new name is not valid, this function will set the status to
1745 * failed and will set also an error in the mail operation
1748 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1749 TnyFolderStore *into,
1750 const gchar *new_name)
1752 if (TNY_IS_ACCOUNT (into) &&
1753 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1754 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1756 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1757 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1758 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1759 _("FIXME: folder name already in use"));
1766 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1768 TnyFolderStore *parent,
1769 gboolean delete_original,
1770 XferMsgsAsynUserCallback user_callback,
1773 ModestMailOperationPrivate *priv = NULL;
1774 ModestTnyFolderRules parent_rules = 0, rules;
1775 XFerMsgAsyncHelper *helper = NULL;
1777 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1778 g_return_if_fail (TNY_IS_FOLDER (folder));
1780 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1782 /* Get account and set it into mail_operation */
1783 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1784 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1786 /* Get folder rules */
1787 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1788 if (TNY_IS_FOLDER (parent))
1789 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1791 /* The moveable restriction is applied also to copy operation */
1792 if ((gpointer) parent == (gpointer) folder ||
1793 (!TNY_IS_FOLDER_STORE (parent)) ||
1794 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1795 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1796 /* Set status failed and set an error */
1797 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1798 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1799 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1800 _("mail_in_ui_folder_move_target_error"));
1802 /* Notify the queue */
1803 modest_mail_operation_notify_end (self);
1804 } else if (TNY_IS_FOLDER (parent) &&
1805 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1806 /* Set status failed and set an error */
1807 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1808 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1809 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1810 _("FIXME: parent folder does not accept new folders"));
1812 /* Notify the queue */
1813 modest_mail_operation_notify_end (self);
1817 /* Check that the new folder name is not used by any
1818 special local folder */
1819 if (new_name_valid_if_local_account (priv, parent,
1820 tny_folder_get_name (folder))) {
1821 /* Create the helper */
1822 helper = g_slice_new0 (XFerMsgAsyncHelper);
1823 helper->mail_op = g_object_ref(self);
1824 helper->dest_folder = NULL;
1825 helper->headers = NULL;
1826 helper->user_callback = user_callback;
1827 helper->user_data = user_data;
1829 /* Move/Copy folder */
1830 tny_folder_copy_async (folder,
1832 tny_folder_get_name (folder),
1835 transfer_folder_status_cb,
1838 modest_mail_operation_notify_end (self);
1844 modest_mail_operation_rename_folder (ModestMailOperation *self,
1848 ModestMailOperationPrivate *priv;
1849 ModestTnyFolderRules rules;
1850 XFerMsgAsyncHelper *helper;
1852 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1853 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1854 g_return_if_fail (name);
1856 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1858 /* Get account and set it into mail_operation */
1859 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1861 /* Check folder rules */
1862 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1863 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1864 /* Set status failed and set an error */
1865 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1866 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1867 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1868 _("FIXME: unable to rename"));
1870 /* Notify about operation end */
1871 modest_mail_operation_notify_end (self);
1872 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1873 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1874 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1875 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1876 _("FIXME: unable to rename"));
1877 /* Notify about operation end */
1878 modest_mail_operation_notify_end (self);
1880 TnyFolderStore *into;
1882 into = tny_folder_get_folder_store (folder);
1884 /* Check that the new folder name is not used by any
1885 special local folder */
1886 if (new_name_valid_if_local_account (priv, into, name)) {
1887 /* Create the helper */
1888 helper = g_slice_new0 (XFerMsgAsyncHelper);
1889 helper->mail_op = g_object_ref(self);
1890 helper->dest_folder = NULL;
1891 helper->headers = NULL;
1892 helper->user_callback = NULL;
1893 helper->user_data = NULL;
1895 /* Rename. Camel handles folder subscription/unsubscription */
1896 tny_folder_copy_async (folder, into, name, TRUE,
1898 transfer_folder_status_cb,
1901 modest_mail_operation_notify_end (self);
1903 g_object_unref (into);
1907 /* ******************************************************************* */
1908 /* ************************** MSG ACTIONS ************************* */
1909 /* ******************************************************************* */
1911 void modest_mail_operation_get_msg (ModestMailOperation *self,
1913 GetMsgAsyncUserCallback user_callback,
1916 GetMsgAsyncHelper *helper = NULL;
1918 ModestMailOperationPrivate *priv;
1920 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1921 g_return_if_fail (TNY_IS_HEADER (header));
1923 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1924 folder = tny_header_get_folder (header);
1926 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1928 /* Get message from folder */
1930 /* Get account and set it into mail_operation */
1931 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1933 helper = g_slice_new0 (GetMsgAsyncHelper);
1934 helper->mail_op = self;
1935 helper->user_callback = user_callback;
1936 helper->user_data = user_data;
1937 helper->header = g_object_ref (header);
1939 // The callback's reference so that the mail op is not
1940 // finalized until the async operation is completed even if
1941 // the user canceled the request meanwhile.
1942 g_object_ref (G_OBJECT (helper->mail_op));
1944 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1946 g_object_unref (G_OBJECT (folder));
1948 /* Set status failed and set an error */
1949 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1950 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1951 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1952 _("Error trying to get a message. No folder found for header"));
1954 /* Notify the queue */
1955 modest_mail_operation_notify_end (self);
1960 get_msg_cb (TnyFolder *folder,
1966 GetMsgAsyncHelper *helper = NULL;
1967 ModestMailOperation *self = NULL;
1968 ModestMailOperationPrivate *priv = NULL;
1970 helper = (GetMsgAsyncHelper *) user_data;
1971 g_return_if_fail (helper != NULL);
1972 self = helper->mail_op;
1973 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1974 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1976 /* Check errors and cancel */
1978 priv->error = g_error_copy (*error);
1979 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1980 } else if (cancelled) {
1981 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1982 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1983 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1984 _("Error trying to refresh the contents of %s"),
1985 tny_folder_get_name (folder));
1987 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1990 /* If user defined callback function was defined, call it even
1991 if the operation failed*/
1992 if (helper->user_callback) {
1993 /* This callback is called into an iddle by tinymail,
1994 and idles are not in the main lock */
1995 gdk_threads_enter ();
1996 helper->user_callback (self, helper->header, msg, helper->user_data);
1997 gdk_threads_leave ();
2000 /* Notify about operation end */
2001 modest_mail_operation_notify_end (self);
2003 g_object_unref (helper->mail_op);
2004 g_object_unref (helper->header);
2005 g_slice_free (GetMsgAsyncHelper, helper);
2010 get_msg_status_cb (GObject *obj,
2014 GetMsgAsyncHelper *helper = NULL;
2015 ModestMailOperation *self;
2016 ModestMailOperationPrivate *priv;
2017 ModestMailOperationState *state;
2019 g_return_if_fail (status != NULL);
2020 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2022 helper = (GetMsgAsyncHelper *) user_data;
2023 g_return_if_fail (helper != NULL);
2025 self = helper->mail_op;
2026 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2031 state = modest_mail_operation_clone_state (self);
2032 state->bytes_done = status->position;
2033 state->bytes_total = status->of_total;
2034 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2035 gdk_threads_enter ();
2037 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2038 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2039 gdk_threads_leave ();
2041 g_slice_free (ModestMailOperationState, state);
2044 /****************************************************/
2046 ModestMailOperation *mail_op;
2048 GetMsgAsyncUserCallback user_callback;
2050 GDestroyNotify notify;
2054 GetMsgAsyncUserCallback user_callback;
2058 ModestMailOperation *mail_op;
2059 } NotifyGetMsgsInfo;
2063 * Used by get_msgs_full_thread to call the user_callback for each
2064 * message that has been read
2067 notify_get_msgs_full (gpointer data)
2069 NotifyGetMsgsInfo *info;
2071 info = (NotifyGetMsgsInfo *) data;
2073 /* Call the user callback. Idles are not in the main lock, so
2075 gdk_threads_enter ();
2076 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2077 gdk_threads_leave ();
2079 g_slice_free (NotifyGetMsgsInfo, info);
2085 * Used by get_msgs_full_thread to free al the thread resources and to
2086 * call the destroy function for the passed user_data
2089 get_msgs_full_destroyer (gpointer data)
2091 GetFullMsgsInfo *info;
2093 info = (GetFullMsgsInfo *) data;
2096 gdk_threads_enter ();
2097 info->notify (info->user_data);
2098 gdk_threads_leave ();
2102 g_object_unref (info->headers);
2103 g_slice_free (GetFullMsgsInfo, info);
2109 get_msgs_full_thread (gpointer thr_user_data)
2111 GetFullMsgsInfo *info;
2112 ModestMailOperationPrivate *priv = NULL;
2113 TnyIterator *iter = NULL;
2115 info = (GetFullMsgsInfo *) thr_user_data;
2116 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2118 iter = tny_list_create_iterator (info->headers);
2119 while (!tny_iterator_is_done (iter)) {
2123 header = TNY_HEADER (tny_iterator_get_current (iter));
2124 folder = tny_header_get_folder (header);
2126 /* Get message from folder */
2129 /* The callback will call it per each header */
2130 msg = tny_folder_get_msg (folder, header, &(priv->error));
2133 ModestMailOperationState *state;
2138 /* notify progress */
2139 state = modest_mail_operation_clone_state (info->mail_op);
2140 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2141 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2142 pair, (GDestroyNotify) modest_pair_free);
2144 /* The callback is the responsible for
2145 freeing the message */
2146 if (info->user_callback) {
2147 NotifyGetMsgsInfo *info_notify;
2148 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2149 info_notify->user_callback = info->user_callback;
2150 info_notify->mail_op = info->mail_op;
2151 info_notify->header = g_object_ref (header);
2152 info_notify->msg = g_object_ref (msg);
2153 info_notify->user_data = info->user_data;
2154 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2155 notify_get_msgs_full,
2158 g_object_unref (msg);
2161 /* Set status failed and set an error */
2162 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2163 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2164 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2165 "Error trying to get a message. No folder found for header");
2169 g_object_unref (header);
2171 tny_iterator_next (iter);
2174 /* Set operation status */
2175 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2176 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2178 /* Notify about operation end */
2179 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2181 /* Free thread resources. Will be called after all previous idles */
2182 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2188 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2189 TnyList *header_list,
2190 GetMsgAsyncUserCallback user_callback,
2192 GDestroyNotify notify)
2194 TnyHeader *header = NULL;
2195 TnyFolder *folder = NULL;
2197 ModestMailOperationPrivate *priv = NULL;
2198 GetFullMsgsInfo *info = NULL;
2199 gboolean size_ok = TRUE;
2201 TnyIterator *iter = NULL;
2203 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2205 /* Init mail operation */
2206 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2207 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2209 priv->total = tny_list_get_length(header_list);
2211 /* Get account and set it into mail_operation */
2212 if (tny_list_get_length (header_list) >= 1) {
2213 iter = tny_list_create_iterator (header_list);
2214 header = TNY_HEADER (tny_iterator_get_current (iter));
2216 folder = tny_header_get_folder (header);
2218 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2220 g_object_unref (folder);
2223 g_object_unref (header);
2226 if (tny_list_get_length (header_list) == 1) {
2227 g_object_unref (iter);
2232 /* Get msg size limit */
2233 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2234 MODEST_CONF_MSG_SIZE_LIMIT,
2237 g_clear_error (&(priv->error));
2238 max_size = G_MAXINT;
2240 max_size = max_size * KB;
2243 /* Check message size limits. If there is only one message
2244 always retrieve it */
2246 while (!tny_iterator_is_done (iter) && size_ok) {
2247 header = TNY_HEADER (tny_iterator_get_current (iter));
2249 if (tny_header_get_message_size (header) >= max_size)
2251 g_object_unref (header);
2254 tny_iterator_next (iter);
2256 g_object_unref (iter);
2260 /* Create the info */
2261 info = g_slice_new0 (GetFullMsgsInfo);
2262 info->mail_op = self;
2263 info->user_callback = user_callback;
2264 info->user_data = user_data;
2265 info->headers = g_object_ref (header_list);
2266 info->notify = notify;
2268 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2270 /* Set status failed and set an error */
2271 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2272 /* FIXME: the error msg is different for pop */
2273 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2274 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2275 _("emev_ni_ui_imap_msg_size_exceed_error"));
2276 /* Remove from queue and free resources */
2277 modest_mail_operation_notify_end (self);
2285 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2286 gboolean remove_to_trash /*ignored*/)
2289 ModestMailOperationPrivate *priv;
2291 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2292 g_return_if_fail (TNY_IS_HEADER (header));
2294 if (remove_to_trash)
2295 g_warning ("remove to trash is not implemented");
2297 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2298 folder = tny_header_get_folder (header);
2300 /* Get account and set it into mail_operation */
2301 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2303 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2306 tny_folder_remove_msg (folder, header, &(priv->error));
2308 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2309 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2311 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2312 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2313 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2314 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2317 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2323 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2325 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2328 g_object_unref (G_OBJECT (folder));
2330 /* Notify about operation end */
2331 modest_mail_operation_notify_end (self);
2335 transfer_msgs_status_cb (GObject *obj,
2339 XFerMsgAsyncHelper *helper = NULL;
2340 ModestMailOperation *self;
2341 ModestMailOperationPrivate *priv;
2342 ModestMailOperationState *state;
2345 g_return_if_fail (status != NULL);
2346 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2348 helper = (XFerMsgAsyncHelper *) user_data;
2349 g_return_if_fail (helper != NULL);
2351 self = helper->mail_op;
2352 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2354 priv->done = status->position;
2355 priv->total = status->of_total;
2357 state = modest_mail_operation_clone_state (self);
2358 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2359 gdk_threads_enter ();
2361 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2362 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2363 gdk_threads_leave ();
2365 g_slice_free (ModestMailOperationState, state);
2370 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2372 XFerMsgAsyncHelper *helper;
2373 ModestMailOperation *self;
2374 ModestMailOperationPrivate *priv;
2376 helper = (XFerMsgAsyncHelper *) user_data;
2377 self = helper->mail_op;
2379 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2382 priv->error = g_error_copy (*err);
2384 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2385 } else if (cancelled) {
2386 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2387 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2388 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2389 _("Error trying to refresh the contents of %s"),
2390 tny_folder_get_name (folder));
2393 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2396 /* Notify about operation end */
2397 modest_mail_operation_notify_end (self);
2399 /* If user defined callback function was defined, call it */
2400 if (helper->user_callback) {
2401 gdk_threads_enter ();
2402 helper->user_callback (priv->source, helper->user_data);
2403 gdk_threads_leave ();
2407 g_object_unref (helper->headers);
2408 g_object_unref (helper->dest_folder);
2409 g_object_unref (helper->mail_op);
2410 g_slice_free (XFerMsgAsyncHelper, helper);
2411 g_object_unref (folder);
2416 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2419 gboolean delete_original,
2420 XferMsgsAsynUserCallback user_callback,
2423 ModestMailOperationPrivate *priv = NULL;
2424 TnyIterator *iter = NULL;
2425 TnyFolder *src_folder = NULL;
2426 XFerMsgAsyncHelper *helper = NULL;
2427 TnyHeader *header = NULL;
2428 ModestTnyFolderRules rules = 0;
2429 const gchar *id1 = NULL;
2430 const gchar *id2 = NULL;
2431 gboolean same_folder = FALSE;
2433 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2434 g_return_if_fail (TNY_IS_LIST (headers));
2435 g_return_if_fail (TNY_IS_FOLDER (folder));
2437 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2440 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2442 /* Apply folder rules */
2443 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2444 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2445 /* Set status failed and set an error */
2446 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2447 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2448 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2449 _CS("ckct_ib_unable_to_paste_here"));
2450 /* Notify the queue */
2451 modest_mail_operation_notify_end (self);
2455 /* Get source folder */
2456 iter = tny_list_create_iterator (headers);
2457 header = TNY_HEADER (tny_iterator_get_current (iter));
2459 src_folder = tny_header_get_folder (header);
2460 g_object_unref (header);
2463 g_object_unref (iter);
2465 /* Check folder source and destination */
2466 id1 = tny_folder_get_id (src_folder);
2467 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2468 same_folder = !g_ascii_strcasecmp (id1, id2);
2470 /* Set status failed and set an error */
2471 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2472 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2473 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2474 _("mcen_ib_unable_to_copy_samefolder"));
2476 /* Notify the queue */
2477 modest_mail_operation_notify_end (self);
2480 g_object_unref (src_folder);
2484 /* Create the helper */
2485 helper = g_slice_new0 (XFerMsgAsyncHelper);
2486 helper->mail_op = g_object_ref(self);
2487 helper->dest_folder = g_object_ref(folder);
2488 helper->headers = g_object_ref(headers);
2489 helper->user_callback = user_callback;
2490 helper->user_data = user_data;
2492 /* Get account and set it into mail_operation */
2493 priv->account = modest_tny_folder_get_account (src_folder);
2495 /* Transfer messages */
2496 tny_folder_transfer_msgs_async (src_folder,
2501 transfer_msgs_status_cb,
2507 on_refresh_folder (TnyFolder *folder,
2512 RefreshAsyncHelper *helper = NULL;
2513 ModestMailOperation *self = NULL;
2514 ModestMailOperationPrivate *priv = NULL;
2516 helper = (RefreshAsyncHelper *) user_data;
2517 self = helper->mail_op;
2518 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2521 priv->error = g_error_copy (*error);
2522 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2527 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2528 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2529 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2530 _("Error trying to refresh the contents of %s"),
2531 tny_folder_get_name (folder));
2535 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2537 /* Call user defined callback, if it exists */
2538 if (helper->user_callback) {
2539 gdk_threads_enter ();
2540 helper->user_callback (self, folder, helper->user_data);
2541 gdk_threads_leave ();
2545 g_slice_free (RefreshAsyncHelper, helper);
2547 /* Notify about operation end */
2548 modest_mail_operation_notify_end (self);
2552 on_refresh_folder_status_update (GObject *obj,
2556 RefreshAsyncHelper *helper = NULL;
2557 ModestMailOperation *self = NULL;
2558 ModestMailOperationPrivate *priv = NULL;
2559 ModestMailOperationState *state;
2561 g_return_if_fail (user_data != NULL);
2562 g_return_if_fail (status != NULL);
2563 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2565 helper = (RefreshAsyncHelper *) user_data;
2566 self = helper->mail_op;
2567 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2569 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2571 priv->done = status->position;
2572 priv->total = status->of_total;
2574 state = modest_mail_operation_clone_state (self);
2575 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2576 gdk_threads_enter ();
2578 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2579 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2580 gdk_threads_leave ();
2582 g_slice_free (ModestMailOperationState, state);
2586 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2588 RefreshAsyncUserCallback user_callback,
2591 ModestMailOperationPrivate *priv = NULL;
2592 RefreshAsyncHelper *helper = NULL;
2594 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2596 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2598 /* Get account and set it into mail_operation */
2599 priv->account = modest_tny_folder_get_account (folder);
2601 /* Create the helper */
2602 helper = g_slice_new0 (RefreshAsyncHelper);
2603 helper->mail_op = self;
2604 helper->user_callback = user_callback;
2605 helper->user_data = user_data;
2607 /* Refresh the folder. TODO: tinymail could issue a status
2608 updates before the callback call then this could happen. We
2609 must review the design */
2610 tny_folder_refresh_async (folder,
2612 on_refresh_folder_status_update,
2618 * It's used by the mail operation queue to notify the observers
2619 * attached to that signal that the operation finished. We need to use
2620 * that because tinymail does not give us the progress of a given
2621 * operation when it finishes (it directly calls the operation
2625 modest_mail_operation_notify_end (ModestMailOperation *self)
2627 ModestMailOperationState *state;
2628 ModestMailOperationPrivate *priv = NULL;
2630 g_return_if_fail (self);
2632 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2634 /* Set the account back to not busy */
2635 if (priv->account_name) {
2636 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2637 priv->account_name, FALSE);
2638 g_free(priv->account_name);
2639 priv->account_name = NULL;
2642 /* Notify the observers about the mail operation end */
2643 /* We do not wrapp this emission because we assume that this
2644 function is always called from within the main lock */
2645 state = modest_mail_operation_clone_state (self);
2646 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2647 g_slice_free (ModestMailOperationState, state);