Composer autosave cleanups.
This simplifies the async autosave logic and improves error handling. Hoping this will solve bug #616987 but I've yet to reproduce it myself.
This commit is contained in:
@ -99,23 +99,30 @@ composer_autosave_state_free (AutosaveState *state)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
composer_autosave_state_open (AutosaveState *state)
|
||||
composer_autosave_state_open (AutosaveState *state,
|
||||
GError **error)
|
||||
{
|
||||
const gchar *user_data_dir;
|
||||
gchar *path;
|
||||
gint fd;
|
||||
|
||||
if (state->file != NULL)
|
||||
return TRUE;
|
||||
|
||||
path = g_build_filename (
|
||||
e_get_user_data_dir (), AUTOSAVE_SEED, NULL);
|
||||
user_data_dir = e_get_user_data_dir ();
|
||||
path = g_build_filename (user_data_dir, AUTOSAVE_SEED, NULL);
|
||||
|
||||
/* Since GIO doesn't have support for creating temporary files
|
||||
* from a template (and in a given directory), we have to use
|
||||
* g_mkstemp(), which brings a small risk of overwriting another
|
||||
* autosave file. The risk is, however, miniscule. */
|
||||
errno = 0;
|
||||
fd = g_mkstemp (path);
|
||||
if (fd == -1) {
|
||||
g_set_error (
|
||||
error, G_FILE_ERROR,
|
||||
g_file_error_from_errno (errno),
|
||||
"%s", g_strerror (errno));
|
||||
g_free (path);
|
||||
return FALSE;
|
||||
}
|
||||
@ -317,72 +324,31 @@ e_composer_autosave_unregister (EMsgComposer *composer)
|
||||
g_object_set_data (G_OBJECT (composer), "autosave", NULL);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
EMsgComposer *composer;
|
||||
GSimpleAsyncResult *simple;
|
||||
AutosaveState *state;
|
||||
|
||||
/* Transient data */
|
||||
GInputStream *input_stream;
|
||||
} AutosaveData;
|
||||
|
||||
static void
|
||||
autosave_data_free (AutosaveData *data)
|
||||
{
|
||||
g_object_unref (data->composer);
|
||||
g_object_unref (data->simple);
|
||||
|
||||
if (data->input_stream != NULL)
|
||||
g_object_unref (data->input_stream);
|
||||
|
||||
g_slice_free (AutosaveData, data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
autosave_snapshot_check_for_error (AutosaveData *data,
|
||||
GError *error)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
|
||||
if (error == NULL)
|
||||
return FALSE;
|
||||
|
||||
simple = data->simple;
|
||||
g_simple_async_result_set_from_error (simple, error);
|
||||
g_simple_async_result_set_op_res_gboolean (simple, FALSE);
|
||||
g_simple_async_result_complete (simple);
|
||||
g_error_free (error);
|
||||
|
||||
autosave_data_free (data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
autosave_snapshot_splice_cb (GOutputStream *output_stream,
|
||||
GAsyncResult *result,
|
||||
AutosaveData *data)
|
||||
GSimpleAsyncResult *simple)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
GError *error = NULL;
|
||||
|
||||
g_output_stream_splice_finish (output_stream, result, &error);
|
||||
|
||||
if (autosave_snapshot_check_for_error (data, error))
|
||||
return;
|
||||
if (error != NULL) {
|
||||
g_simple_async_result_set_from_error (simple, error);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
simple = data->simple;
|
||||
g_simple_async_result_set_op_res_gboolean (simple, TRUE);
|
||||
g_simple_async_result_complete (simple);
|
||||
|
||||
autosave_data_free (data);
|
||||
g_object_unref (simple);
|
||||
}
|
||||
|
||||
static void
|
||||
autosave_snapshot_cb (GFile *file,
|
||||
GAsyncResult *result,
|
||||
AutosaveData *data)
|
||||
GSimpleAsyncResult *simple)
|
||||
{
|
||||
GObject *object;
|
||||
EMsgComposer *composer;
|
||||
CamelMimeMessage *message;
|
||||
GFileOutputStream *output_stream;
|
||||
GInputStream *input_stream;
|
||||
@ -390,22 +356,26 @@ autosave_snapshot_cb (GFile *file,
|
||||
GByteArray *buffer;
|
||||
GError *error = NULL;
|
||||
|
||||
object = g_async_result_get_source_object (G_ASYNC_RESULT (simple));
|
||||
|
||||
output_stream = g_file_replace_finish (file, result, &error);
|
||||
|
||||
if (autosave_snapshot_check_for_error (data, error))
|
||||
if (error != NULL) {
|
||||
g_simple_async_result_set_from_error (simple, error);
|
||||
g_simple_async_result_complete (simple);
|
||||
g_object_unref (simple);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Extract a MIME message from the composer. */
|
||||
message = e_msg_composer_get_message_draft (data->composer);
|
||||
if (message == NULL) {
|
||||
GSimpleAsyncResult *simple;
|
||||
|
||||
/* FIXME Need to set a GError here. */
|
||||
simple = data->simple;
|
||||
g_simple_async_result_set_op_res_gboolean (simple, FALSE);
|
||||
composer = E_MSG_COMPOSER (object);
|
||||
message = e_msg_composer_get_message_draft (composer, &error);
|
||||
if (error != NULL) {
|
||||
g_simple_async_result_set_from_error (simple, error);
|
||||
g_simple_async_result_complete (simple);
|
||||
g_object_unref (output_stream);
|
||||
autosave_data_free (data);
|
||||
g_object_unref (simple);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -430,7 +400,6 @@ autosave_snapshot_cb (GFile *file,
|
||||
buffer->data, (gssize) buffer->len,
|
||||
(GDestroyNotify) g_free);
|
||||
g_byte_array_free (buffer, FALSE);
|
||||
data->input_stream = input_stream;
|
||||
|
||||
/* Splice the input and output streams */
|
||||
g_output_stream_splice_async (
|
||||
@ -438,9 +407,10 @@ autosave_snapshot_cb (GFile *file,
|
||||
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
|
||||
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
|
||||
G_PRIORITY_DEFAULT, NULL, (GAsyncReadyCallback)
|
||||
autosave_snapshot_splice_cb, data);
|
||||
autosave_snapshot_splice_cb, simple);
|
||||
|
||||
g_object_unref (output_stream);
|
||||
g_object_unref (input_stream);
|
||||
}
|
||||
|
||||
void
|
||||
@ -448,48 +418,39 @@ e_composer_autosave_snapshot_async (EMsgComposer *composer,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
AutosaveData *data;
|
||||
AutosaveState *state;
|
||||
GSimpleAsyncResult *simple;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
|
||||
|
||||
state = g_object_get_data (G_OBJECT (composer), "autosave");
|
||||
g_return_if_fail (state != NULL);
|
||||
|
||||
simple = g_simple_async_result_new (
|
||||
G_OBJECT (composer), callback, user_data,
|
||||
e_composer_autosave_snapshot_async);
|
||||
|
||||
/* If the contents are unchanged, exit early. */
|
||||
if (!gtkhtml_editor_get_changed (GTKHTML_EDITOR (composer))) {
|
||||
g_simple_async_result_set_op_res_gboolean (simple, TRUE);
|
||||
g_simple_async_result_complete (simple);
|
||||
g_object_unref (simple);
|
||||
return;
|
||||
}
|
||||
|
||||
state = g_object_get_data (G_OBJECT (composer), "autosave");
|
||||
g_return_if_fail (state != NULL);
|
||||
|
||||
/* Open the autosave file on-demand. */
|
||||
errno = 0;
|
||||
if (!composer_autosave_state_open (state)) {
|
||||
g_simple_async_result_set_error (
|
||||
simple, G_FILE_ERROR,
|
||||
g_file_error_from_errno (errno),
|
||||
"%s", g_strerror (errno));
|
||||
g_simple_async_result_set_op_res_gboolean (simple, FALSE);
|
||||
if (!composer_autosave_state_open (state, &error)) {
|
||||
g_simple_async_result_set_from_error (simple, error);
|
||||
g_simple_async_result_complete (simple);
|
||||
g_object_unref (simple);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Overwrite the file */
|
||||
data = g_slice_new (AutosaveData);
|
||||
data->composer = g_object_ref (composer);
|
||||
data->simple = simple;
|
||||
data->state = state;
|
||||
|
||||
/* Overwrite the file. */
|
||||
g_file_replace_async (
|
||||
state->file, NULL, FALSE, G_FILE_CREATE_PRIVATE,
|
||||
G_PRIORITY_DEFAULT, NULL, (GAsyncReadyCallback)
|
||||
autosave_snapshot_cb, data);
|
||||
autosave_snapshot_cb, simple);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -498,17 +459,15 @@ e_composer_autosave_snapshot_finish (EMsgComposer *composer,
|
||||
GError **error)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
gboolean success;
|
||||
|
||||
g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), FALSE);
|
||||
g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
simple = G_SIMPLE_ASYNC_RESULT (result);
|
||||
success = g_simple_async_result_get_op_res_gboolean (simple);
|
||||
g_simple_async_result_propagate_error (simple, error);
|
||||
|
||||
return success;
|
||||
/* Success is assumed in the absense of a GError. */
|
||||
return !g_simple_async_result_propagate_error (simple, error);
|
||||
}
|
||||
|
||||
gchar *
|
||||
|
||||
@ -596,7 +596,8 @@ account_hash_algo_to_camel_hash (const gchar *hash_algo)
|
||||
static CamelMimeMessage *
|
||||
build_message (EMsgComposer *composer,
|
||||
gboolean html_content,
|
||||
gboolean save_html_object_data)
|
||||
gboolean save_html_object_data,
|
||||
GError **error)
|
||||
{
|
||||
GtkhtmlEditor *editor;
|
||||
EMsgComposerPrivate *p = composer->priv;
|
||||
@ -1149,20 +1150,14 @@ exception:
|
||||
|
||||
g_object_unref (new);
|
||||
|
||||
if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
e_alert_run_dialog_for_args (
|
||||
(GtkWindow *) composer,
|
||||
"mail-composer:no-build-message",
|
||||
local_error->message, NULL);
|
||||
|
||||
g_error_free (local_error);
|
||||
|
||||
if (recipients) {
|
||||
for (i=0; i<recipients->len; i++)
|
||||
g_free (recipients->pdata[i]);
|
||||
g_ptr_array_free (recipients, TRUE);
|
||||
}
|
||||
|
||||
g_propagate_error (error, local_error);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -3781,7 +3776,8 @@ e_msg_composer_add_inline_image_from_mime_part (EMsgComposer *composer,
|
||||
**/
|
||||
CamelMimeMessage *
|
||||
e_msg_composer_get_message (EMsgComposer *composer,
|
||||
gboolean save_html_object_data)
|
||||
gboolean save_html_object_data,
|
||||
GError **error)
|
||||
{
|
||||
EAttachmentView *view;
|
||||
EAttachmentStore *store;
|
||||
@ -3803,7 +3799,9 @@ e_msg_composer_get_message (EMsgComposer *composer,
|
||||
editor = GTKHTML_EDITOR (composer);
|
||||
html_content = gtkhtml_editor_get_html_mode (editor);
|
||||
|
||||
return build_message (composer, html_content, save_html_object_data);
|
||||
return build_message (
|
||||
composer, html_content,
|
||||
save_html_object_data, error);
|
||||
}
|
||||
|
||||
static gchar *
|
||||
@ -3859,7 +3857,8 @@ e_msg_composer_get_message_print (EMsgComposer *composer,
|
||||
editor = GTKHTML_EDITOR (composer);
|
||||
html_content = gtkhtml_editor_get_html_mode (editor);
|
||||
|
||||
msg = build_message (composer, html_content, save_html_object_data);
|
||||
msg = build_message (
|
||||
composer, html_content, save_html_object_data, NULL);
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
|
||||
@ -3871,7 +3870,8 @@ e_msg_composer_get_message_print (EMsgComposer *composer,
|
||||
flags = msg_composer_get_message_print_helper (
|
||||
temp_composer, html_content);
|
||||
|
||||
msg = build_message (temp_composer, TRUE, save_html_object_data);
|
||||
msg = build_message (
|
||||
temp_composer, TRUE, save_html_object_data, NULL);
|
||||
if (msg != NULL)
|
||||
camel_medium_set_header (
|
||||
CAMEL_MEDIUM (msg), "X-Evolution-Format", flags);
|
||||
@ -3883,7 +3883,8 @@ e_msg_composer_get_message_print (EMsgComposer *composer,
|
||||
}
|
||||
|
||||
CamelMimeMessage *
|
||||
e_msg_composer_get_message_draft (EMsgComposer *composer)
|
||||
e_msg_composer_get_message_draft (EMsgComposer *composer,
|
||||
GError **error)
|
||||
{
|
||||
GtkhtmlEditor *editor;
|
||||
EComposerHeaderTable *table;
|
||||
@ -3917,7 +3918,7 @@ e_msg_composer_get_message_draft (EMsgComposer *composer)
|
||||
smime_encrypt = gtk_toggle_action_get_active (action);
|
||||
gtk_toggle_action_set_active (action, FALSE);
|
||||
|
||||
msg = build_message (composer, TRUE, TRUE);
|
||||
msg = build_message (composer, TRUE, TRUE, error);
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
|
||||
@ -3933,9 +3934,6 @@ e_msg_composer_get_message_draft (EMsgComposer *composer)
|
||||
action = GTK_TOGGLE_ACTION (ACTION (SMIME_ENCRYPT));
|
||||
gtk_toggle_action_set_active (action, smime_encrypt);
|
||||
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Attach account info to the draft. */
|
||||
account = e_composer_header_table_get_account (table);
|
||||
if (account && account->name)
|
||||
|
||||
@ -114,14 +114,16 @@ void e_msg_composer_add_inline_image_from_mime_part
|
||||
CamelMimePart *part);
|
||||
CamelMimeMessage *
|
||||
e_msg_composer_get_message (EMsgComposer *composer,
|
||||
gboolean save_html_object_data);
|
||||
gboolean save_html_object_data,
|
||||
GError **error);
|
||||
CamelMimeMessage *
|
||||
e_msg_composer_get_message_print
|
||||
(EMsgComposer *composer,
|
||||
gboolean save_html_object_data);
|
||||
CamelMimeMessage *
|
||||
e_msg_composer_get_message_draft
|
||||
(EMsgComposer *composer);
|
||||
(EMsgComposer *composer,
|
||||
GError **error);
|
||||
void e_msg_composer_show_sig_file (EMsgComposer *composer);
|
||||
|
||||
CamelInternetAddress *
|
||||
|
||||
@ -299,6 +299,7 @@ composer_get_message (EMsgComposer *composer, gboolean save_html_object_data)
|
||||
EComposerHeaderTable *table;
|
||||
EComposerHeader *post_to_header;
|
||||
GString *invalid_addrs = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
gconf = mail_config_get_gconf_client ();
|
||||
table = e_msg_composer_get_header_table (composer);
|
||||
@ -469,9 +470,27 @@ composer_get_message (EMsgComposer *composer, gboolean save_html_object_data)
|
||||
goto finished;
|
||||
|
||||
/* actually get the message now, this will sign/encrypt etc */
|
||||
message = e_msg_composer_get_message (composer, save_html_object_data);
|
||||
if (message == NULL)
|
||||
message = e_msg_composer_get_message (
|
||||
composer, save_html_object_data, &error);
|
||||
|
||||
/* Ignore cancellations. */
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
||||
g_warn_if_fail (message == NULL);
|
||||
g_error_free (error);
|
||||
goto finished;
|
||||
}
|
||||
|
||||
if (error != NULL) {
|
||||
g_warn_if_fail (message == NULL);
|
||||
e_alert_run_dialog_for_args (
|
||||
GTK_WINDOW (composer),
|
||||
"mail-composer:no-build-message",
|
||||
error->message, NULL);
|
||||
g_error_free (error);
|
||||
goto finished;
|
||||
}
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
|
||||
|
||||
/* Add info about the sending account */
|
||||
account = e_composer_header_table_get_account (table);
|
||||
@ -636,6 +655,7 @@ em_utils_composer_save_draft_cb (EMsgComposer *composer)
|
||||
CamelMimeMessage *msg;
|
||||
CamelMessageInfo *info;
|
||||
EAccount *account;
|
||||
GError *error = NULL;
|
||||
|
||||
/* need to get stuff from the composer here, since it could
|
||||
* get destroyed while we're in mail_msg_wait() a little lower
|
||||
@ -646,13 +666,32 @@ em_utils_composer_save_draft_cb (EMsgComposer *composer)
|
||||
local_drafts_folder_uri =
|
||||
e_mail_local_get_folder_uri (E_MAIL_FOLDER_DRAFTS);
|
||||
|
||||
g_object_ref (composer);
|
||||
msg = e_msg_composer_get_message_draft (composer);
|
||||
msg = e_msg_composer_get_message_draft (composer, &error);
|
||||
|
||||
/* Ignore cancellations. */
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
||||
g_warn_if_fail (msg == NULL);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (error != NULL) {
|
||||
g_warn_if_fail (msg == NULL);
|
||||
e_alert_run_dialog_for_args (
|
||||
GTK_WINDOW (composer),
|
||||
"mail-composer:no-build-message",
|
||||
error->message, NULL);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
g_return_if_fail (CAMEL_IS_MIME_MESSAGE (msg));
|
||||
|
||||
table = e_msg_composer_get_header_table (composer);
|
||||
account = e_composer_header_table_get_account (table);
|
||||
|
||||
sdi = g_malloc (sizeof(struct _save_draft_info));
|
||||
sdi->composer = composer;
|
||||
sdi->composer = g_object_ref (composer);
|
||||
sdi->emcs = g_object_get_data (G_OBJECT (composer), "emcs");
|
||||
if (sdi->emcs)
|
||||
emcs_ref (sdi->emcs);
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
#include <mail/mail-session.h>
|
||||
#include <mail/mail-ops.h>
|
||||
#include <mail/message-list.h>
|
||||
#include <e-util/e-alert-dialog.h>
|
||||
#include <e-util/e-plugin.h>
|
||||
#include <e-util/e-util.h>
|
||||
#include <shell/e-shell-view.h>
|
||||
@ -670,14 +671,37 @@ action_template_cb (GtkAction *action,
|
||||
CamelMessageInfo *info;
|
||||
CamelMimeMessage *msg;
|
||||
CamelFolder *folder;
|
||||
GError *error = NULL;
|
||||
|
||||
/* Get the templates folder and all UIDs of the messages there. */
|
||||
folder = e_mail_local_get_folder (E_MAIL_FOLDER_TEMPLATES);
|
||||
|
||||
msg = e_msg_composer_get_message_draft (composer);
|
||||
msg = e_msg_composer_get_message_draft (composer, &error);
|
||||
|
||||
/* Ignore cancellations. */
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
||||
g_warn_if_fail (msg == NULL);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (error != NULL) {
|
||||
g_warn_if_fail (msg == NULL);
|
||||
e_alert_run_dialog_for_args (
|
||||
GTK_WINDOW (composer),
|
||||
"mail-composer:no-build-message",
|
||||
error->message, NULL);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
g_return_if_fail (CAMEL_IS_MIME_MESSAGE (msg));
|
||||
|
||||
info = camel_message_info_new (NULL);
|
||||
|
||||
/* FIXME: what's the ~0 for? :) */
|
||||
/* The last argument is a bit mask which tells the function
|
||||
* which flags to modify. In this case, ~0 means all flags.
|
||||
* So it clears all the flags and then sets SEEN and DRAFT. */
|
||||
camel_message_info_set_flags (
|
||||
info, CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DRAFT, ~0);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user