X-Git-Url: http://git.maemo.org/git/?p=modest;a=blobdiff_plain;f=src%2Fmodest-mail-operation.c;h=6bd42b3d678c9f23a5beb151a80d6e7f951853fc;hp=3f0f98a2f5357b8038cdff84e601ff1c12a3919c;hb=ff041741b15caa9e663249315645251362eb4924;hpb=778ad5b3bcc7d9244900a0a801851fb796bab6d5 diff --git a/src/modest-mail-operation.c b/src/modest-mail-operation.c index 3f0f98a..6bd42b3 100644 --- a/src/modest-mail-operation.c +++ b/src/modest-mail-operation.c @@ -95,9 +95,7 @@ static void notify_progress_of_multiple_messages (ModestMailOperation *self, gint total_bytes, gboolean increment_done); -static guint compute_message_list_size (TnyList *headers); - -static guint compute_message_array_size (GPtrArray *headers); +static guint compute_message_list_size (TnyList *headers, guint num_elements); static int compare_headers_by_date (gconstpointer a, gconstpointer b); @@ -107,6 +105,37 @@ static void sync_folder_finish_callback (TnyFolder *self, GError *err, gpointer user_data); +static gboolean _check_memory_low (ModestMailOperation *mail_op); + +/* Helpers for the update account operation (send & receive)*/ +typedef struct +{ + ModestMailOperation *mail_op; + gchar *account_name; + UpdateAccountCallback callback; + gpointer user_data; + TnyList *folders; + gint pending_calls; + gboolean poke_all; + TnyFolderObserver *inbox_observer; + RetrieveAllCallback retrieve_all_cb; + gboolean interactive; + gboolean msg_readed; +} UpdateAccountInfo; + +static void destroy_update_account_info (UpdateAccountInfo *info); + +static void update_account_send_mail (UpdateAccountInfo *info); + +static void update_account_get_msg_async_cb (TnyFolder *folder, + gboolean canceled, + TnyMsg *msg, + GError *err, + gpointer user_data); + +static void update_account_notify_user_and_free (UpdateAccountInfo *info, + TnyList *new_headers); + enum _ModestMailOperationSignals { PROGRESS_CHANGED_SIGNAL, @@ -508,7 +537,8 @@ modest_mail_operation_cancel (ModestMailOperation *self) TRUE); /* Cancel the sending of the following next messages */ - tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL); + if (TNY_IS_SEND_QUEUE (queue)) + tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL); } return canceled; @@ -600,55 +630,61 @@ modest_mail_operation_clone_state (ModestMailOperation *self) /* ************************** SEND ACTIONS ************************* */ /* ******************************************************************* */ -void -modest_mail_operation_send_mail (ModestMailOperation *self, - TnyTransportAccount *transport_account, - TnyMsg* msg) +typedef struct +{ + ModestMailOperation *mail_op; + gboolean notify; +} SendNewMailHelper; + +static void +send_mail_common_cb (gboolean cancelled, + GError *err, + SendNewMailHelper *helper) { - TnySendQueue *send_queue = NULL; ModestMailOperationPrivate *priv; - - g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self)); - g_return_if_fail (transport_account && TNY_IS_TRANSPORT_ACCOUNT (transport_account)); - g_return_if_fail (msg && TNY_IS_MSG (msg)); - - priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self); + ModestMailOperation *self; - /* Get account and set it into mail_operation */ - priv->account = g_object_ref (transport_account); - priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; - priv->done = 1; - priv->total = 1; + self = helper->mail_op; + priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self); - send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account, TRUE)); - if (!TNY_IS_SEND_QUEUE(send_queue)) { - if (priv->error) { - g_error_free (priv->error); - priv->error = NULL; - } - g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR, - MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND, - "modest: could not find send queue for account\n"); - priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED; - modest_mail_operation_notify_end (self); + if (cancelled || err) + goto end; + if (err) { + g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR, + MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR, + "Error adding a msg to the send queue\n"); + priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS; } else { - /* Add the msg to the queue */ - modest_mail_operation_notify_start (self); - - tny_send_queue_add_async (send_queue, msg, NULL, NULL, NULL); - modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue), FALSE); + priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS; + } - if (priv->error) { - priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS; - } else { - priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS; - } + end: + if (helper->notify) modest_mail_operation_notify_end (self); - } + g_object_unref (helper->mail_op); + g_slice_free (SendNewMailHelper, helper); +} + +static void +send_mail_on_sync_async_cb (TnyFolder *self, + gboolean cancelled, + GError *err, + gpointer user_data) +{ + send_mail_common_cb (cancelled, err, (SendNewMailHelper *) user_data); } +static void +send_mail_on_added_to_outbox (TnySendQueue *send_queue, + gboolean cancelled, + TnyMsg *msg, + GError *err, + gpointer user_data) +{ + send_mail_common_cb (cancelled, err, (SendNewMailHelper *) user_data); +} static gboolean idle_create_msg_cb (gpointer idle_data) @@ -676,18 +712,19 @@ create_msg_thread (gpointer thread_data) CreateMsgInfo *info = (CreateMsgInfo *) thread_data; TnyMsg *new_msg = NULL; ModestMailOperationPrivate *priv; + gint attached = 0; priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op); if (info->html_body == NULL) { new_msg = modest_tny_msg_new (info->to, info->from, info->cc, info->bcc, info->subject, info->plain_body, - info->attachments_list, + info->attachments_list, &attached, &(priv->error)); } else { new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc, info->bcc, info->subject, info->html_body, info->plain_body, info->attachments_list, - info->images_list, + info->images_list, &attached, &(priv->error)); } @@ -699,7 +736,7 @@ create_msg_thread (gpointer thread_data) tny_header_set_flag (header, info->priority_flags); /* Set attachment flags in message */ - if (info->attachments_list != NULL) + if (info->attachments_list != NULL && attached > 0) tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS); g_object_unref (G_OBJECT(header)); @@ -790,6 +827,7 @@ modest_mail_operation_send_new_mail_cb (ModestMailOperation *self, TnyMsg *msg, gpointer userdata) { + TnySendQueue *send_queue = NULL; ModestMailOperationPrivate *priv = NULL; SendNewMailInfo *info = (SendNewMailInfo *) userdata; TnyFolder *draft_folder = NULL; @@ -810,8 +848,31 @@ modest_mail_operation_send_new_mail_cb (ModestMailOperation *self, goto end; } - /* Call mail operation */ - modest_mail_operation_send_mail (self, info->transport_account, msg); + /* Add message to send queue */ + send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE)); + if (!TNY_IS_SEND_QUEUE(send_queue)) { + if (priv->error) { + g_error_free (priv->error); + priv->error = NULL; + } + g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR, + MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND, + "modest: could not find send queue for account\n"); + priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED; + modest_mail_operation_notify_end (self); + goto end; + } else { + SendNewMailHelper *helper = g_slice_new (SendNewMailHelper); + helper->mail_op = g_object_ref (self); + helper->notify = (info->draft_msg == NULL); + + /* Add the msg to the queue. The callback will free + the helper */ + modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue), + FALSE); + tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox, + NULL, helper); + } if (info->draft_msg != NULL) { TnyList *tmp_headers = NULL; @@ -819,6 +880,7 @@ modest_mail_operation_send_new_mail_cb (ModestMailOperation *self, TnyFolder *src_folder = NULL; TnyFolderType folder_type; TnyTransportAccount *transport_account = NULL; + SendNewMailHelper *helper = NULL; /* To remove the old mail from its source folder, we need to get the * transport account of the original draft message (the transport account @@ -837,16 +899,21 @@ modest_mail_operation_send_new_mail_cb (ModestMailOperation *self, if (!draft_folder) { g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder", __FUNCTION__); + modest_mail_operation_notify_end (self); goto end; } if (!outbox_folder) { g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder", __FUNCTION__); + modest_mail_operation_notify_end (self); goto end; } folder = tny_msg_get_folder (info->draft_msg); - if (folder == NULL) goto end; + if (folder == NULL) { + modest_mail_operation_notify_end (self); + goto end; + } folder_type = modest_tny_folder_guess_folder_type (folder); if (folder_type == TNY_FOLDER_TYPE_INVALID) @@ -859,12 +926,16 @@ modest_mail_operation_send_new_mail_cb (ModestMailOperation *self, /* Note: This can fail (with a warning) if the message is not really already in a folder, * because this function requires it to have a UID. */ + helper = g_slice_new (SendNewMailHelper); + helper->mail_op = g_object_ref (self); + helper->notify = TRUE; + tmp_headers = tny_simple_list_new (); tny_list_append (tmp_headers, (GObject*) header); tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL); g_object_unref (tmp_headers); - tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */ - + tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb, + NULL, helper); g_object_unref (folder); } @@ -904,7 +975,9 @@ modest_mail_operation_send_new_mail (ModestMailOperation *self, priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; priv->account = TNY_ACCOUNT (g_object_ref (transport_account)); priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS; - + + modest_mail_operation_notify_start (self); + /* Check parametters */ if (to == NULL) { /* Set status failed and set an error */ @@ -912,6 +985,7 @@ modest_mail_operation_send_new_mail (ModestMailOperation *self, g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR, MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER, _("Error trying to send a mail. You need to set at least one recipient")); + modest_mail_operation_notify_end (self); return; } info = g_slice_new0 (SendNewMailInfo); @@ -923,7 +997,6 @@ modest_mail_operation_send_new_mail (ModestMailOperation *self, g_object_ref (draft_msg); - modest_mail_operation_notify_start (self); modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body, attachments_list, images_list, priority_flags, modest_mail_operation_send_new_mail_cb, info); @@ -1144,7 +1217,7 @@ static void foreach_add_item (gpointer header, gpointer user_data) { tny_list_prepend (TNY_LIST (user_data), - g_object_ref (G_OBJECT (header))); + G_OBJECT (header)); } /* This is the method that looks for new messages in a folder */ @@ -1202,21 +1275,6 @@ internal_folder_observer_class_init (InternalFolderObserverClass *klass) object_class->finalize = internal_folder_observer_finalize; } -typedef struct -{ - ModestMailOperation *mail_op; - gchar *account_name; - UpdateAccountCallback callback; - gpointer user_data; - TnyList *folders; - gint pending_calls; - gboolean poke_all; - TnyFolderObserver *inbox_observer; - RetrieveAllCallback retrieve_all_cb; - gboolean interactive; -} UpdateAccountInfo; - - static void destroy_update_account_info (UpdateAccountInfo *info) { @@ -1226,6 +1284,49 @@ destroy_update_account_info (UpdateAccountInfo *info) g_slice_free (UpdateAccountInfo, info); } + +static void +update_account_send_mail (UpdateAccountInfo *info) +{ + TnyTransportAccount *transport_account = NULL; + + /* Get the transport account */ + transport_account = (TnyTransportAccount *) + modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(), + info->account_name); + + if (transport_account) { + ModestTnySendQueue *send_queue; + TnyFolder *outbox; + guint num_messages; + + send_queue = modest_runtime_get_send_queue (transport_account, TRUE); + g_object_unref (transport_account); + + if (TNY_IS_SEND_QUEUE (send_queue)) { + /* Get outbox folder */ + outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue)); + if (outbox) { /* this could fail in some cases */ + num_messages = tny_folder_get_all_count (outbox); + g_object_unref (outbox); + } else { + g_warning ("%s: could not get outbox", __FUNCTION__); + num_messages = 0; + } + + if (num_messages != 0) { + /* Reenable suspended items */ + modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue)); + + /* Try to send */ + tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue)); + modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue), + info->interactive); + } + } + } +} + static void update_account_get_msg_async_cb (TnyFolder *folder, gboolean canceled, @@ -1234,12 +1335,55 @@ update_account_get_msg_async_cb (TnyFolder *folder, gpointer user_data) { GetMsgInfo *msg_info = (GetMsgInfo *) user_data; + ModestMailOperationPrivate *priv; + + priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op); + priv->done++; - /* Just delete the helper. Don't do anything with the new - msg. There is also no need to check for errors */ - g_object_unref (msg_info->mail_op); - g_object_unref (msg_info->header); - g_slice_free (GetMsgInfo, msg_info); + if (TNY_IS_MSG (msg)) { + TnyHeader *header = tny_msg_get_header (msg); + + if (header) { + ModestMailOperationState *state; + state = modest_mail_operation_clone_state (msg_info->mail_op); + msg_info->sum_total_bytes += tny_header_get_message_size (header); + state->bytes_done = msg_info->sum_total_bytes; + state->bytes_total = msg_info->total_bytes; + + /* Notify the status change. Only notify about changes + referred to bytes */ + g_signal_emit (G_OBJECT (msg_info->mail_op), + signals[PROGRESS_CHANGED_SIGNAL], + 0, state, NULL); + + g_object_unref (header); + g_slice_free (ModestMailOperationState, state); + } + } + + if (priv->done == priv->total) { + TnyList *new_headers; + UpdateAccountInfo *info; + + /* After getting all the messages send the ones in the + outboxes */ + info = (UpdateAccountInfo *) msg_info->user_data; + update_account_send_mail (info); + + /* Check if the operation was a success */ + if (!priv->error) + priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS; + + /* Call the user callback and free */ + new_headers = tny_iterator_get_list (msg_info->more_msgs); + update_account_notify_user_and_free (info, new_headers); + g_object_unref (new_headers); + + /* Delete the helper */ + g_object_unref (msg_info->more_msgs); + g_object_unref (msg_info->mail_op); + g_slice_free (GetMsgInfo, msg_info); + } } static void @@ -1278,12 +1422,14 @@ inbox_refreshed_cb (TnyFolder *inbox, ModestAccountRetrieveType retrieve_type; TnyList *new_headers = NULL; gboolean headers_only, ignore_limit; - TnyTransportAccount *transport_account = NULL; info = (UpdateAccountInfo *) user_data; priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op); mgr = modest_runtime_get_account_mgr (); + /* Set the last updated as the current time, do it even if the inbox refresh failed */ + modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL)); + if (canceled || err) { priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED; if (err) @@ -1292,6 +1438,11 @@ inbox_refreshed_cb (TnyFolder *inbox, g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR, MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED, "canceled"); + + tny_folder_remove_observer (inbox, info->inbox_observer); + g_object_unref (info->inbox_observer); + info->inbox_observer = NULL; + /* Notify the user about the error and then exit */ update_account_notify_user_and_free (info, NULL); return; @@ -1313,28 +1464,30 @@ inbox_refreshed_cb (TnyFolder *inbox, /* Create the new headers array. We need it to sort the new headers by date */ new_headers_array = g_ptr_array_new (); - new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers); - while (!tny_iterator_is_done (new_headers_iter)) { - TnyHeader *header = NULL; - - header = TNY_HEADER (tny_iterator_get_current (new_headers_iter)); - /* Apply per-message size limits */ - if (tny_header_get_message_size (header) < max_size) - g_ptr_array_add (new_headers_array, g_object_ref (header)); - - g_object_unref (header); - tny_iterator_next (new_headers_iter); + if (info->inbox_observer) { + new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers); + while (!tny_iterator_is_done (new_headers_iter)) { + TnyHeader *header = NULL; + + header = TNY_HEADER (tny_iterator_get_current (new_headers_iter)); + /* Apply per-message size limits */ + if (tny_header_get_message_size (header) < max_size) + g_ptr_array_add (new_headers_array, g_object_ref (header)); + + g_object_unref (header); + tny_iterator_next (new_headers_iter); + } + g_object_unref (new_headers_iter); + + tny_folder_remove_observer (inbox, info->inbox_observer); + g_object_unref (info->inbox_observer); + info->inbox_observer = NULL; } - g_object_unref (new_headers_iter); - tny_folder_remove_observer (inbox, info->inbox_observer); - g_object_unref (info->inbox_observer); - info->inbox_observer = NULL; - /* Update the last updated key, even if we don't have to get new headers */ - modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL)); - - if (new_headers_array->len == 0) + if (new_headers_array->len == 0) { + g_ptr_array_free (new_headers_array, FALSE); goto send_mail; + } /* Get per-account message amount retrieval limit */ retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name); @@ -1361,85 +1514,64 @@ inbox_refreshed_cb (TnyFolder *inbox, new_headers_array->len, retrieve_limit); } + + /* Copy the headers to a list and free the array */ + new_headers = tny_simple_list_new (); + for (i=0; i < new_headers_array->len; i++) { + TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i)); + tny_list_append (new_headers, G_OBJECT (header)); + } + g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL); + g_ptr_array_free (new_headers_array, FALSE); - if (!headers_only) { + if (!headers_only && (tny_list_get_length (new_headers) > 0)) { gint msg_num = 0; - const gint msg_list_size = compute_message_array_size (new_headers_array); + TnyIterator *iter; + GetMsgInfo *msg_info; priv->done = 0; if (ignore_limit) - priv->total = new_headers_array->len; + priv->total = tny_list_get_length (new_headers); else - priv->total = MIN (new_headers_array->len, retrieve_limit); - while (msg_num < priv->total) { - TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num)); - TnyFolder *folder = tny_header_get_folder (header); - GetMsgInfo *msg_info; + priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit); + + iter = tny_list_create_iterator (new_headers); + + /* Create the message info */ + msg_info = g_slice_new0 (GetMsgInfo); + msg_info->mail_op = g_object_ref (info->mail_op); + msg_info->total_bytes = compute_message_list_size (new_headers, priv->total); + msg_info->more_msgs = g_object_ref (iter); + msg_info->user_data = info; - /* Create the message info */ - msg_info = g_slice_new0 (GetMsgInfo); - msg_info->mail_op = g_object_ref (info->mail_op); - msg_info->header = g_object_ref (header); - msg_info->total_bytes = msg_list_size; + while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) { + TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter)); + TnyFolder *folder = tny_header_get_folder (header); /* Get message in an async way */ tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb, - get_msg_status_cb, msg_info); + NULL, msg_info); g_object_unref (folder); msg_num++; + tny_iterator_next (iter); } - } + g_object_unref (iter); - /* Copy the headers to a list and free the array */ - new_headers = tny_simple_list_new (); - for (i=0; i < new_headers_array->len; i++) { - TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i)); - tny_list_append (new_headers, G_OBJECT (header)); + /* The mail operation will finish when the last + message is retrieved */ + return; } - g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL); - g_ptr_array_free (new_headers_array, FALSE); - send_mail: - /* Get the transport account */ - transport_account = (TnyTransportAccount *) - modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(), - info->account_name); - - if (transport_account) { - ModestTnySendQueue *send_queue; - TnyFolder *outbox; - guint num_messages; - - send_queue = modest_runtime_get_send_queue (transport_account, TRUE); - g_object_unref (transport_account); - - /* Get outbox folder */ - outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue)); - if (outbox) { /* this could fail in some cases */ - num_messages = tny_folder_get_all_count (outbox); - g_object_unref (outbox); - } else { - g_warning ("%s: could not get outbox", __FUNCTION__); - num_messages = 0; - } - - if (num_messages != 0) { - /* Reenable suspended items */ - modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue)); - - /* Try to send */ - tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue)); - modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue), - info->interactive); - } - } - + /* If we don't have to retrieve the new messages then + simply send mail */ + update_account_send_mail (info); + /* Check if the operation was a success */ if (!priv->error) priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS; - + /* Call the user callback and free */ update_account_notify_user_and_free (info, new_headers); } @@ -2200,6 +2332,7 @@ modest_mail_operation_rename_folder (ModestMailOperation *self, void modest_mail_operation_get_msg (ModestMailOperation *self, TnyHeader *header, + gboolean progress_feedback, GetMsgAsyncUserCallback user_callback, gpointer user_data) { @@ -2211,20 +2344,31 @@ modest_mail_operation_get_msg (ModestMailOperation *self, g_return_if_fail (TNY_IS_HEADER (header)); priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self); - folder = tny_header_get_folder (header); - priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS; priv->total = 1; priv->done = 0; + /* Check memory low */ + if (_check_memory_low (self)) { + if (user_callback) + user_callback (self, header, FALSE, NULL, priv->error, user_data); + modest_mail_operation_notify_end (self); + return; + } + /* Get account and set it into mail_operation */ + folder = tny_header_get_folder (header); priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder)); /* Check for cached messages */ - if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) - priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN; - else - priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE; + if (progress_feedback) { + if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) + priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN; + else + priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE; + } else { + priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN; + } /* Create the helper */ helper = g_slice_new0 (GetMsgInfo); @@ -2247,6 +2391,7 @@ modest_mail_operation_get_msg (ModestMailOperation *self, state->total = 0; g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL); + g_slice_free (ModestMailOperationState, state); tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper); @@ -2376,6 +2521,28 @@ modest_mail_operation_get_msgs_full (ModestMailOperation *self, priv->done = 0; priv->total = tny_list_get_length(header_list); + /* Check memory low */ + if (_check_memory_low (self)) { + if (user_callback) { + TnyHeader *header = NULL; + TnyIterator *iter; + + if (tny_list_get_length (header_list) > 0) { + iter = tny_list_create_iterator (header_list); + header = (TnyHeader *) tny_iterator_get_current (iter); + g_object_unref (iter); + } + user_callback (self, header, FALSE, NULL, priv->error, user_data); + if (header) + g_object_unref (header); + } + if (notify) + notify (user_data); + /* Notify about operation end */ + modest_mail_operation_notify_end (self); + return; + } + /* Check uncached messages */ for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE; !has_uncached_messages && !tny_iterator_is_done (iter); @@ -2405,7 +2572,7 @@ modest_mail_operation_get_msgs_full (ModestMailOperation *self, g_object_unref (iterator); } - msg_list_size = compute_message_list_size (header_list); + msg_list_size = compute_message_list_size (header_list, 0); modest_mail_operation_notify_start (self); iter = tny_list_create_iterator (header_list); @@ -2547,22 +2714,25 @@ modest_mail_operation_remove_msgs (ModestMailOperation *self, if (traccount) { ModestTnySendQueueStatus status; ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE); - TnyIterator *iter = tny_list_create_iterator(headers); - g_object_unref(remove_headers); - remove_headers = TNY_LIST(tny_simple_list_new()); - while (!tny_iterator_is_done(iter)) { - char *msg_id; - TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter)); - msg_id = modest_tny_send_queue_get_msg_id (hdr); - status = modest_tny_send_queue_get_msg_status(send_queue, msg_id); - if (status != MODEST_TNY_SEND_QUEUE_SENDING) { - tny_list_append(remove_headers, G_OBJECT(hdr)); + + if (TNY_IS_SEND_QUEUE (send_queue)) { + TnyIterator *iter = tny_list_create_iterator(headers); + g_object_unref(remove_headers); + remove_headers = TNY_LIST(tny_simple_list_new()); + while (!tny_iterator_is_done(iter)) { + char *msg_id; + TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter)); + msg_id = modest_tny_send_queue_get_msg_id (hdr); + status = modest_tny_send_queue_get_msg_status(send_queue, msg_id); + if (status != MODEST_TNY_SEND_QUEUE_SENDING) { + tny_list_append(remove_headers, G_OBJECT(hdr)); + } + g_object_unref(hdr); + g_free(msg_id); + tny_iterator_next(iter); } - g_object_unref(hdr); - g_free(msg_id); - tny_iterator_next(iter); + g_object_unref(iter); } - g_object_unref(iter); g_object_unref(traccount); } } @@ -2661,6 +2831,35 @@ transfer_msgs_status_cb (GObject *obj, &(helper->sum_total_bytes), helper->total_bytes, TRUE); } +static void +transfer_msgs_sync_folder_cb (TnyFolder *self, + gboolean cancelled, + GError *err, + gpointer user_data) +{ + XFerMsgsAsyncHelper *helper; + /* We don't care here about the results of the + synchronization */ + helper = (XFerMsgsAsyncHelper *) user_data; + + /* Notify about operation end */ + modest_mail_operation_notify_end (helper->mail_op); + + /* If user defined callback function was defined, call it */ + if (helper->user_callback) + helper->user_callback (helper->mail_op, helper->user_data); + + /* Free */ + if (helper->more_msgs) + g_object_unref (helper->more_msgs); + if (helper->headers) + g_object_unref (helper->headers); + if (helper->dest_folder) + g_object_unref (helper->dest_folder); + if (helper->mail_op) + g_object_unref (helper->mail_op); + g_slice_free (XFerMsgsAsyncHelper, helper); +} static void transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data) @@ -2702,34 +2901,13 @@ transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer u } if (finished) { - - /* Update folder counts */ - tny_folder_poke_status (folder); - tny_folder_poke_status (helper->dest_folder); - - /* Notify about operation end */ - modest_mail_operation_notify_end (self); - - /* If user defined callback function was defined, call it */ - if (helper->user_callback) { - /* This is not a GDK lock because we are a Tinymail callback and - * Tinymail already acquires the Gdk lock */ - - /* no gdk_threads_enter (), CHECKED */ - helper->user_callback (self, helper->user_data); - /* no gdk_threads_leave (), CHECKED */ - } - - /* Free */ - if (helper->more_msgs) - g_object_unref (helper->more_msgs); - if (helper->headers) - g_object_unref (helper->headers); - if (helper->dest_folder) - g_object_unref (helper->dest_folder); - if (helper->mail_op) - g_object_unref (helper->mail_op); - g_slice_free (XFerMsgsAsyncHelper, helper); + /* Synchronize the source folder contents. This should + be done by tinymail but the camel_folder_sync it's + actually disabled in transfer_msgs_thread_clean + because it's supposed to cause hangs */ + tny_folder_sync_async (folder, helper->delete, + transfer_msgs_sync_folder_cb, + NULL, helper); } else { /* Transfer more messages */ tny_folder_transfer_msgs_async (folder, @@ -2742,39 +2920,33 @@ transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer u } } +/* Computes the size of the messages the headers in the list belongs + to. If num_elements is different from 0 then it only takes into + account the first num_elements for the calculation */ static guint -compute_message_list_size (TnyList *headers) +compute_message_list_size (TnyList *headers, + guint num_elements) { TnyIterator *iter; - guint size = 0; + guint size = 0, element = 0; + + /* If num_elements is not valid then take all into account */ + if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers))) + num_elements = tny_list_get_length (headers); iter = tny_list_create_iterator (headers); - while (!tny_iterator_is_done (iter)) { + while (!tny_iterator_is_done (iter) && element < num_elements) { TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter)); size += tny_header_get_message_size (header); g_object_unref (header); tny_iterator_next (iter); + element++; } g_object_unref (iter); return size; } -static guint -compute_message_array_size (GPtrArray *headers) -{ - guint size = 0; - gint i; - - for (i = 0; i < headers->len; i++) { - TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i)); - size += tny_header_get_message_size (header); - } - - return size; -} - - void modest_mail_operation_xfer_msgs (ModestMailOperation *self, TnyList *headers, @@ -2791,6 +2963,7 @@ modest_mail_operation_xfer_msgs (ModestMailOperation *self, ModestTnyFolderRules rules = 0; TnyAccount *dst_account = NULL; gboolean leave_on_server; + ModestMailOperationState *state; g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self)); g_return_if_fail (headers && TNY_IS_LIST (headers)); @@ -2857,7 +3030,7 @@ modest_mail_operation_xfer_msgs (ModestMailOperation *self, helper->user_data = user_data; helper->last_total_bytes = 0; helper->sum_total_bytes = 0; - helper->total_bytes = compute_message_list_size (headers); + helper->total_bytes = compute_message_list_size (headers, 0); /* Get account and set it into mail_operation */ priv->account = modest_tny_folder_get_account (src_folder); @@ -2902,6 +3075,14 @@ modest_mail_operation_xfer_msgs (ModestMailOperation *self, helper->delete = (leave_on_server) ? FALSE : delete_original; modest_mail_operation_notify_start (self); + + /* Start notifying progress */ + state = modest_mail_operation_clone_state (self); + state->done = 0; + state->total = 0; + g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL); + g_slice_free (ModestMailOperationState, state); + tny_folder_transfer_msgs_async (src_folder, helper->headers, folder, @@ -3010,9 +3191,17 @@ modest_mail_operation_refresh_folder (ModestMailOperation *self, priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self); - priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS; + /* Check memory low */ + if (_check_memory_low (self)) { + if (user_callback) + user_callback (self, folder, user_data); + /* Notify about operation end */ + modest_mail_operation_notify_end (self); + return; + } /* Get account and set it into mail_operation */ + priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS; priv->account = modest_tny_folder_get_account (folder); priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE; @@ -3031,8 +3220,7 @@ modest_mail_operation_refresh_folder (ModestMailOperation *self, state->total = 0; g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL); - - /* FIXME: we're leaking the state here, or? valgrind thinks so */ + g_slice_free (ModestMailOperationState, state); tny_folder_refresh_async (folder, on_refresh_folder, @@ -3056,6 +3244,7 @@ run_queue_stop (ModestTnySendQueue *queue, g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self); g_object_unref (self); } + void modest_mail_operation_run_queue (ModestMailOperation *self, ModestTnySendQueue *queue) @@ -3076,6 +3265,42 @@ modest_mail_operation_run_queue (ModestMailOperation *self, } static void +shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata) +{ + ModestMailOperation *self = (ModestMailOperation *) userdata; + ModestMailOperationPrivate *priv; + + g_return_if_fail (MODEST_IS_MAIL_OPERATION (self)); + g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store)); + priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self); + + priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS; + + modest_mail_operation_notify_end (self); + g_object_unref (self); +} + +void +modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store) +{ + ModestMailOperationPrivate *priv; + + g_return_if_fail (MODEST_IS_MAIL_OPERATION (self)); + g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store)); + priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self); + + modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ()); + + priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS; + priv->account = NULL; + priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN; + + modest_mail_operation_notify_start (self); + g_object_ref (self); + modest_tny_account_store_shutdown (account_store, shutdown_callback, self); +} + +static void sync_folder_finish_callback (TnyFolder *self, gboolean cancelled, GError *err, @@ -3248,3 +3473,25 @@ modest_mail_operation_to_string (ModestMailOperation *self) priv->done, priv->total, priv->error && priv->error->message ? priv->error->message : ""); } + +/* + * Once the mail operations were objects this will be no longer + * needed. I don't like it, but we need it for the moment + */ +static gboolean +_check_memory_low (ModestMailOperation *mail_op) +{ + if (modest_platform_check_memory_low (NULL, FALSE)) { + ModestMailOperationPrivate *priv; + + priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op); + priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED; + g_set_error (&(priv->error), + MODEST_MAIL_OPERATION_ERROR, + MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY, + "Not enough memory to complete the operation"); + return TRUE; + } else { + return FALSE; + } +}