aboutsummaryrefslogtreecommitdiffstats
path: root/mail/em-composer-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'mail/em-composer-utils.c')
-rw-r--r--mail/em-composer-utils.c1010
1 files changed, 539 insertions, 471 deletions
diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c
index 11143124e0..316046eecd 100644
--- a/mail/em-composer-utils.c
+++ b/mail/em-composer-utils.c
@@ -44,8 +44,10 @@
#include "shell/e-shell.h"
+#include "e-mail-folder-utils.h"
#include "e-mail-local.h"
#include "e-mail-session.h"
+#include "e-mail-session-utils.h"
#include "em-utils.h"
#include "em-composer-utils.h"
#include "composer/e-msg-composer.h"
@@ -69,97 +71,32 @@
#define GCONF_KEY_TEMPLATE_PLACEHOLDERS "/apps/evolution/mail/template_placeholders"
-static void em_utils_composer_send_cb (EMsgComposer *composer);
-static void em_utils_composer_save_draft_cb (EMsgComposer *composer);
+typedef struct _AsyncContext AsyncContext;
-struct emcs_t {
- guint ref_count;
-
- CamelFolder *drafts_folder;
- gchar *drafts_uid;
-
- CamelFolder *folder;
- guint32 flags, set;
- gchar *uid;
+struct _AsyncContext {
+ CamelMimeMessage *message;
+ EMsgComposer *composer;
+ EActivity *activity;
+ gchar *folder_uri;
+ gchar *message_uid;
};
-static struct emcs_t *
-emcs_new (void)
-{
- struct emcs_t *emcs;
-
- emcs = g_new0 (struct emcs_t, 1);
- emcs->ref_count = 1;
-
- return emcs;
-}
-
-static void
-emcs_set_drafts_info (struct emcs_t *emcs,
- CamelFolder *drafts_folder,
- const gchar *drafts_uid)
-{
- g_return_if_fail (emcs != NULL);
- g_return_if_fail (drafts_folder != NULL);
- g_return_if_fail (drafts_uid != NULL);
-
- if (emcs->drafts_folder != NULL)
- g_object_unref (emcs->drafts_folder);
- g_free (emcs->drafts_uid);
-
- g_object_ref (drafts_folder);
- emcs->drafts_folder = drafts_folder;
- emcs->drafts_uid = g_strdup (drafts_uid);
-}
-
-static void
-emcs_set_folder_info (struct emcs_t *emcs,
- CamelFolder *folder,
- const gchar *uid,
- guint32 flags,
- guint32 set)
-{
- g_return_if_fail (emcs != NULL);
- g_return_if_fail (folder != NULL);
- g_return_if_fail (uid != NULL);
-
- if (emcs->folder != NULL)
- g_object_unref (emcs->folder);
- g_free (emcs->uid);
-
- g_object_ref (folder);
- emcs->folder = folder;
- emcs->uid = g_strdup (uid);
- emcs->flags = flags;
- emcs->set = set;
-}
-
static void
-free_emcs (struct emcs_t *emcs)
+async_context_free (AsyncContext *context)
{
- if (emcs->drafts_folder != NULL)
- g_object_unref (emcs->drafts_folder);
- g_free (emcs->drafts_uid);
+ if (context->message != NULL)
+ g_object_unref (context->message);
- if (emcs->folder != NULL)
- g_object_unref (emcs->folder);
- g_free (emcs->uid);
+ if (context->composer != NULL)
+ g_object_unref (context->composer);
- g_free (emcs);
-}
+ if (context->activity != NULL)
+ g_object_unref (context->activity);
-static void
-emcs_ref (struct emcs_t *emcs)
-{
- emcs->ref_count++;
-}
+ g_free (context->folder_uri);
+ g_free (context->message_uid);
-static void
-emcs_unref (struct emcs_t *emcs)
-{
- emcs->ref_count--;
- if (emcs->ref_count == 0)
- free_emcs (emcs);
+ g_slice_free (AsyncContext, context);
}
static gboolean
@@ -211,69 +148,6 @@ ask_confirm_for_only_bcc (EMsgComposer *composer, gboolean hidden_list_case)
hidden_list_case?"mail:ask-send-only-bcc-contact":"mail:ask-send-only-bcc", NULL);
}
-struct _send_data {
- struct emcs_t *emcs;
- EMsgComposer *composer;
- gboolean send;
-};
-
-static void
-composer_send_queued_cb (CamelFolder *folder, CamelMimeMessage *msg, CamelMessageInfo *info,
- gint queued, const gchar *appended_uid, gpointer data)
-{
- CamelSession *session;
- struct emcs_t *emcs;
- struct _send_data *send = data;
-
- emcs = send->emcs;
-
- session = e_msg_composer_get_session (send->composer);
-
- if (queued) {
- if (emcs && emcs->drafts_folder) {
- /* delete the old draft message */
- camel_folder_set_message_flags (
- emcs->drafts_folder, emcs->drafts_uid,
- CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN,
- CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN);
- g_object_unref (emcs->drafts_folder);
- emcs->drafts_folder = NULL;
- g_free (emcs->drafts_uid);
- emcs->drafts_uid = NULL;
- }
-
- if (emcs && emcs->folder) {
- /* set any replied flags etc */
- camel_folder_set_message_flags (
- emcs->folder, emcs->uid,
- emcs->flags, emcs->set);
- camel_folder_set_message_user_flag (
- emcs->folder, emcs->uid,
- "receipt-handled", TRUE);
- g_object_unref (emcs->folder);
- emcs->folder = NULL;
- g_free (emcs->uid);
- emcs->uid = NULL;
- }
-
- gtk_widget_destroy (GTK_WIDGET (send->composer));
-
- if (send->send && camel_session_get_online (session)) {
- /* queue a message send */
- mail_send (E_MAIL_SESSION (session));
- }
- } else
- gtk_widget_show (GTK_WIDGET (send->composer));
-
- camel_message_info_free (info);
-
- if (send->emcs)
- emcs_unref (send->emcs);
-
- g_object_unref (send->composer);
- g_free (send);
-}
-
static gboolean
is_group_definition (const gchar *str)
{
@@ -286,106 +160,101 @@ is_group_definition (const gchar *str)
return colon > str && strchr (str, ';') > colon;
}
-static CamelMimeMessage *
-composer_get_message (EMsgComposer *composer, gboolean save_html_object_data)
+static gboolean
+composer_presend_check_recipients (EMsgComposer *composer)
{
- CamelMimeMessage *message = NULL;
- EDestination **recipients, **recipients_bcc;
- gboolean html_mode, send_html, confirm_html;
+ EDestination **recipients;
+ EDestination **recipients_bcc;
CamelInternetAddress *cia;
- gint hidden = 0, shown = 0;
- gint num = 0, num_bcc = 0, num_post = 0;
- const gchar *subject;
- GConfClient *gconf;
- EAccount *account;
- gint i;
- EMEvent *eme;
- EMEventTargetComposer *target;
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);
+ gboolean check_passed = FALSE;
+ gint hidden = 0;
+ gint shown = 0;
+ gint num = 0;
+ gint num_bcc = 0;
+ gint num_post = 0;
+ gint ii;
- /* We should do all of the validity checks based on the composer, and not on
- the created message, as extra interaction may occur when we get the message
- (e.g. to get a passphrase to sign a message) */
+ /* We should do all of the validity checks based on the composer,
+ * and not on the created message, as extra interaction may occur
+ * when we get the message (e.g. passphrase to sign a message). */
- /* get the message recipients */
+ table = e_msg_composer_get_header_table (composer);
recipients = e_composer_header_table_get_destinations (table);
cia = camel_internet_address_new ();
- /* see which ones are visible/present, etc */
- if (recipients) {
- for (i = 0; recipients[i] != NULL; i++) {
- const gchar *addr = e_destination_get_address (recipients[i]);
-
- if (addr && addr[0]) {
- gint len, j;
-
- camel_address_decode ((CamelAddress *) cia, addr);
- len = camel_address_length ((CamelAddress *) cia);
-
- if (len > 0) {
- if (!e_destination_is_evolution_list (recipients[i])) {
- for (j = 0; j < len; j++) {
- const gchar *name = NULL, *eml = NULL;
-
- if (!camel_internet_address_get (cia, j, &name, &eml) ||
- !eml ||
- strchr (eml, '@') <= eml) {
- if (!invalid_addrs)
- invalid_addrs = g_string_new ("");
- else
- g_string_append (invalid_addrs, ", ");
-
- if (name)
- g_string_append (invalid_addrs, name);
- if (eml) {
- g_string_append (invalid_addrs, name ? " <" : "");
- g_string_append (invalid_addrs, eml);
- g_string_append (invalid_addrs, name ? ">" : "");
- }
- }
- }
- }
+ /* See which ones are visible, present, etc. */
+ for (ii = 0; recipients != NULL && recipients[ii] != NULL; ii++) {
+ const gchar *addr;
+ gint len, j;
- camel_address_remove ((CamelAddress *) cia, -1);
- num++;
- if (e_destination_is_evolution_list (recipients[i])
- && !e_destination_list_show_addresses (recipients[i])) {
- hidden++;
- } else {
- shown++;
+ addr = e_destination_get_address (recipients[ii]);
+ if (addr == NULL || *addr == '\0')
+ continue;
+
+ camel_address_decode (CAMEL_ADDRESS (cia), addr);
+ len = camel_address_length (CAMEL_ADDRESS (cia));
+
+ if (len > 0) {
+ if (!e_destination_is_evolution_list (recipients[ii])) {
+ for (j = 0; j < len; j++) {
+ const gchar *name = NULL, *eml = NULL;
+
+ if (!camel_internet_address_get (cia, j, &name, &eml) ||
+ !eml ||
+ strchr (eml, '@') <= eml) {
+ if (!invalid_addrs)
+ invalid_addrs = g_string_new ("");
+ else
+ g_string_append (invalid_addrs, ", ");
+
+ if (name)
+ g_string_append (invalid_addrs, name);
+ if (eml) {
+ g_string_append (invalid_addrs, name ? " <" : "");
+ g_string_append (invalid_addrs, eml);
+ g_string_append (invalid_addrs, name ? ">" : "");
+ }
}
- } else if (is_group_definition (addr)) {
- /* like an address, it will not claim on only-bcc */
- shown++;
- num++;
- } else if (!invalid_addrs) {
- invalid_addrs = g_string_new (addr);
- } else {
- g_string_append (invalid_addrs, ", ");
- g_string_append (invalid_addrs, addr);
}
}
+
+ camel_address_remove (CAMEL_ADDRESS (cia), -1);
+ num++;
+ if (e_destination_is_evolution_list (recipients[ii])
+ && !e_destination_list_show_addresses (recipients[ii])) {
+ hidden++;
+ } else {
+ shown++;
+ }
+ } else if (is_group_definition (addr)) {
+ /* like an address, it will not claim on only-bcc */
+ shown++;
+ num++;
+ } else if (!invalid_addrs) {
+ invalid_addrs = g_string_new (addr);
+ } else {
+ g_string_append (invalid_addrs, ", ");
+ g_string_append (invalid_addrs, addr);
}
}
recipients_bcc = e_composer_header_table_get_destinations_bcc (table);
if (recipients_bcc) {
- for (i = 0; recipients_bcc[i] != NULL; i++) {
- const gchar *addr = e_destination_get_address (recipients_bcc[i]);
-
- if (addr && addr[0]) {
- camel_address_decode ((CamelAddress *) cia, addr);
- if (camel_address_length ((CamelAddress *) cia) > 0) {
- camel_address_remove ((CamelAddress *) cia, -1);
- num_bcc++;
- }
+ for (ii = 0; recipients_bcc[ii] != NULL; ii++) {
+ const gchar *addr;
+
+ addr = e_destination_get_address (recipients_bcc[ii]);
+ if (addr == NULL || *addr == '\0')
+ continue;
+
+ camel_address_decode (CAMEL_ADDRESS (cia), addr);
+ if (camel_address_length (CAMEL_ADDRESS (cia)) > 0) {
+ camel_address_remove (CAMEL_ADDRESS (cia), -1);
+ num_bcc++;
}
}
@@ -394,24 +263,32 @@ composer_get_message (EMsgComposer *composer, gboolean save_html_object_data)
g_object_unref (cia);
- post_to_header = e_composer_header_table_get_header (table, E_COMPOSER_HEADER_POST_TO);
+ post_to_header = e_composer_header_table_get_header (
+ table, E_COMPOSER_HEADER_POST_TO);
if (e_composer_header_get_visible (post_to_header)) {
GList *postlist;
postlist = e_composer_header_table_get_post_to (table);
num_post = g_list_length (postlist);
- g_list_foreach (postlist, (GFunc)g_free, NULL);
+ g_list_foreach (postlist, (GFunc) g_free, NULL);
g_list_free (postlist);
}
/* I'm sensing a lack of love, er, I mean recipients. */
if (num == 0 && num_post == 0) {
- e_alert_run_dialog_for_args ((GtkWindow *)composer, "mail:send-no-recipients", NULL);
+ e_alert_submit (
+ GTK_WIDGET (composer),
+ "mail:send-no-recipients", NULL);
goto finished;
}
if (invalid_addrs) {
- if (e_alert_run_dialog_for_args ((GtkWindow *)composer, strstr (invalid_addrs->str, ", ") ? "mail:ask-send-invalid-recip-multi" : "mail:ask-send-invalid-recip-one", invalid_addrs->str, NULL) == GTK_RESPONSE_CANCEL) {
+ if (e_alert_run_dialog_for_args (
+ GTK_WINDOW (composer),
+ strstr (invalid_addrs->str, ", ") ?
+ "mail:ask-send-invalid-recip-multi" :
+ "mail:ask-send-invalid-recip-one",
+ invalid_addrs->str, NULL) == GTK_RESPONSE_CANCEL) {
g_string_free (invalid_addrs, TRUE);
goto finished;
}
@@ -425,154 +302,277 @@ composer_get_message (EMsgComposer *composer, gboolean save_html_object_data)
goto finished;
}
- html_mode = gtkhtml_editor_get_html_mode (GTKHTML_EDITOR (composer));
- send_html = gconf_client_get_bool (gconf, "/apps/evolution/mail/composer/send_html", NULL);
- confirm_html = gconf_client_get_bool (gconf, "/apps/evolution/mail/prompts/unwanted_html", NULL);
+ check_passed = TRUE;
- /* Only show this warning if our default is to send html. If it isn't, we've
- manually switched into html mode in the composer and (presumably) had a good
- reason for doing this. */
- if (html_mode && send_html && confirm_html) {
+finished:
+ if (recipients != NULL)
+ e_destination_freev (recipients);
- gboolean html_problem = FALSE;
+ return check_passed;
+}
- if (recipients) {
- for (i = 0; recipients[i] != NULL && !html_problem; i++) {
- if (!e_destination_get_html_mail_pref (recipients[i]))
- html_problem = TRUE;
- }
- }
+static gboolean
+composer_presend_check_account (EMsgComposer *composer)
+{
+ EComposerHeaderTable *table;
+ EAccount *account;
+ gboolean check_passed;
- if (html_problem) {
- html_problem = !ask_confirm_for_unwanted_html_mail (composer, recipients);
- if (html_problem)
- goto finished;
- }
- }
+ table = e_msg_composer_get_header_table (composer);
+ account = e_composer_header_table_get_account (table);
+ check_passed = (account != NULL && account->enabled);
- /* Check for no subject */
- subject = e_composer_header_table_get_subject (table);
- if (subject == NULL || subject[0] == '\0') {
- if (!ask_confirm_for_empty_subject (composer))
- goto finished;
+ if (!check_passed)
+ e_alert_submit (
+ GTK_WIDGET (composer),
+ "mail:send-no-account-enabled", NULL);
+
+ return check_passed;
+}
+
+static gboolean
+composer_presend_check_downloads (EMsgComposer *composer)
+{
+ EAttachmentView *view;
+ EAttachmentStore *store;
+ gboolean check_passed = TRUE;
+
+ view = e_msg_composer_get_attachment_view (composer);
+ store = e_attachment_view_get_store (view);
+
+ if (e_attachment_store_get_num_loading (store) > 0) {
+ if (!em_utils_prompt_user (GTK_WINDOW (composer), NULL,
+ "mail-composer:ask-send-message-pending-download", NULL))
+ check_passed = FALSE;
}
+ return check_passed;
+}
+
+static gboolean
+composer_presend_check_plugins (EMsgComposer *composer)
+{
+ EMEvent *eme;
+ EMEventTargetComposer *target;
+ gpointer data;
+
/** @Event: composer.presendchecks
* @Title: Composer PreSend Checks
* @Target: EMEventTargetMessage
*
- * composer.presendchecks is emitted during pre-checks for the message just before sending.
- * Since the e-plugin framework doesn't provide a way to return a value from the plugin,
- * use 'presend_check_status' to set whether the check passed / failed.
+ * composer.presendchecks is emitted during pre-checks for the
+ * message just before sending. Since the e-plugin framework
+ * doesn't provide a way to return a value from the plugin,
+ * use 'presend_check_status' to set whether the check passed.
*/
eme = em_event_peek ();
target = em_event_target_new_composer (eme, composer, 0);
- g_object_set_data (G_OBJECT (composer), "presend_check_status", GINT_TO_POINTER(0));
- e_event_emit((EEvent *)eme, "composer.presendchecks", (EEventTarget *)target);
+ e_event_emit (
+ (EEvent *) eme, "composer.presendchecks",
+ (EEventTarget *) target);
- if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (composer), "presend_check_status")))
- goto finished;
+ /* A non-NULL value for this key means the check failed. */
+ data = g_object_get_data (G_OBJECT (composer), "presend_check_status");
- /* actually get the message now, this will sign/encrypt etc */
- message = e_msg_composer_get_message (
- composer, save_html_object_data, NULL, &error);
+ return (data == NULL);
+}
+
+static gboolean
+composer_presend_check_subject (EMsgComposer *composer)
+{
+ EComposerHeaderTable *table;
+ const gchar *subject;
+ gboolean check_passed = TRUE;
+
+ table = e_msg_composer_get_header_table (composer);
+ subject = e_composer_header_table_get_subject (table);
+
+ if (subject == NULL || subject[0] == '\0') {
+ if (!ask_confirm_for_empty_subject (composer))
+ check_passed = FALSE;
+ }
+
+ return check_passed;
+}
+
+static gboolean
+composer_presend_check_unwanted_html (EMsgComposer *composer)
+{
+ EDestination **recipients;
+ EComposerHeaderTable *table;
+ GConfClient *client;
+ gboolean check_passed = TRUE;
+ gboolean html_mode;
+ gboolean send_html;
+ gboolean confirm_html;
+ gint ii;
+
+ client = gconf_client_get_default ();
+
+ table = e_msg_composer_get_header_table (composer);
+ recipients = e_composer_header_table_get_destinations (table);
+ html_mode = gtkhtml_editor_get_html_mode (GTKHTML_EDITOR (composer));
+
+ send_html = gconf_client_get_bool (
+ client, "/apps/evolution/mail/composer/send_html", NULL);
+ confirm_html = gconf_client_get_bool (
+ client, "/apps/evolution/mail/prompts/unwanted_html", NULL);
+
+ /* Only show this warning if our default is to send html. If it
+ * isn't, we've manually switched into html mode in the composer
+ * and (presumably) had a good reason for doing this. */
+ if (html_mode && send_html && confirm_html && recipients != NULL) {
+ gboolean html_problem = FALSE;
+
+ for (ii = 0; recipients[ii] != NULL; ii++) {
+ if (!e_destination_get_html_mail_pref (recipients[ii]))
+ html_problem = TRUE;
+ break;
+ }
+
+ if (html_problem) {
+ if (!ask_confirm_for_unwanted_html_mail (
+ composer, recipients))
+ check_passed = FALSE;
+ }
+ }
+
+ if (recipients != NULL)
+ e_destination_freev (recipients);
+
+ g_object_unref (client);
+
+ return check_passed;
+}
+
+static void
+composer_send_completed (EMailSession *session,
+ GAsyncResult *result,
+ AsyncContext *context)
+{
+ GError *error = NULL;
+
+ e_mail_session_send_to_finish (session, result, &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;
+ goto exit;
}
if (error != NULL) {
- g_warn_if_fail (message == NULL);
- e_alert_run_dialog_for_args (
- GTK_WINDOW (composer),
- "mail-composer:no-build-message",
+ e_alert_submit (
+ GTK_WIDGET (context->composer),
+ "mail-composer:send-error",
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);
-
- if (account) {
- /* FIXME: Why isn't this crap just in e_msg_composer_get_message? */
- camel_medium_set_header (CAMEL_MEDIUM (message), "X-Evolution-Account", account->uid);
- camel_medium_set_header (CAMEL_MEDIUM (message), "X-Evolution-Transport", account->transport->url);
- camel_medium_set_header (CAMEL_MEDIUM (message), "X-Evolution-Fcc", account->sent_folder_uri);
- if (account->id->organization && *account->id->organization) {
- gchar *org;
-
- org = camel_header_encode_string ((const guchar *)account->id->organization);
- camel_medium_set_header (CAMEL_MEDIUM (message), "Organization", org);
- g_free (org);
- }
+ goto exit;
}
- finished:
+ e_activity_complete (context->activity);
- if (recipients)
- e_destination_freev (recipients);
+ /* Wait for the EActivity's completion message to
+ * time out and then destroy the composer window. */
+ g_object_weak_ref (
+ G_OBJECT (context->activity), (GWeakNotify)
+ gtk_widget_destroy, context->composer);
- return message;
+exit:
+ async_context_free (context);
}
static void
-em_utils_composer_send_cb (EMsgComposer *composer)
+composer_send_appended (CamelFolder *outbox_folder,
+ GAsyncResult *result,
+ AsyncContext *context)
{
- EComposerHeaderTable *table;
- CamelMimeMessage *message;
- CamelMessageInfo *info;
- struct _send_data *send;
- CamelFolder *folder;
- EAccount *account;
+ CamelSession *session;
+ GCancellable *cancellable;
+ gchar *message_uid = NULL;
+ GError *error = NULL;
- table = e_msg_composer_get_header_table (composer);
- account = e_composer_header_table_get_account (table);
- if (!account || !account->enabled) {
- e_alert_run_dialog_for_args (
- GTK_WINDOW (composer),
- "mail:send-no-account-enabled", NULL);
+ e_mail_folder_append_message_finish (
+ outbox_folder, result, &message_uid, &error);
+
+ /* Ignore cancellations. */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_warn_if_fail (message_uid == NULL);
+ async_context_free (context);
+ g_error_free (error);
return;
}
- if ((message = composer_get_message (composer, FALSE)) == NULL)
+ if (error != NULL) {
+ g_warn_if_fail (message_uid == NULL);
+ e_alert_submit (
+ GTK_WIDGET (context->composer),
+ "mail-composer:append-to-outbox-error",
+ error->message, NULL);
+ g_warning ("%s", error->message);
+ async_context_free (context);
+ g_error_free (error);
return;
+ }
- folder = e_mail_local_get_folder (E_MAIL_FOLDER_OUTBOX);
- g_object_ref (folder);
+ session = e_msg_composer_get_session (context->composer);
+ cancellable = e_activity_get_cancellable (context->activity);
- /* mail the message */
- e_msg_composer_set_mail_sent (composer, TRUE);
- info = camel_message_info_new (NULL);
+ /* If we're online, go ahead and send the message now. */
+ if (camel_session_get_online (session))
+ e_mail_session_send_to (
+ E_MAIL_SESSION (session),
+ outbox_folder, message_uid, NULL,
+ G_PRIORITY_DEFAULT, cancellable, NULL, NULL,
+ (GAsyncReadyCallback) composer_send_completed,
+ context);
- camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, ~0);
+ /* If we're offline, writing the message to the Outbox
+ * folder is as much as we can do. Tell the user. */
+ else {
+ g_object_unref (context->activity);
+ context->activity = NULL;
- send = g_malloc (sizeof (*send));
- send->emcs = g_object_get_data (G_OBJECT (composer), "emcs");
- if (send->emcs)
- emcs_ref (send->emcs);
- send->send = TRUE;
- send->composer = g_object_ref (composer);
- gtk_widget_hide (GTK_WIDGET (composer));
+ e_alert_run_dialog_for_args (
+ GTK_WINDOW (context->composer),
+ "mail-composer:saved-to-outbox", NULL);
- mail_append_mail (
- folder, message, info, composer_send_queued_cb, send);
+ gtk_widget_destroy (GTK_WIDGET (context->composer));
+ async_context_free (context);
+ }
- g_object_unref (folder);
- g_object_unref (message);
+ g_free (message_uid);
}
-struct _save_draft_info {
- struct emcs_t *emcs;
- EMsgComposer *composer;
+static void
+em_utils_composer_send_cb (EMsgComposer *composer,
+ CamelMimeMessage *message,
+ EActivity *activity)
+{
+ AsyncContext *context;
+ CamelFolder *outbox_folder;
CamelMessageInfo *info;
-};
+ GCancellable *cancellable;
+
+ context = g_slice_new0 (AsyncContext);
+ context->message = g_object_ref (message);
+ context->composer = g_object_ref (composer);
+ context->activity = g_object_ref (activity);
+
+ cancellable = e_activity_get_cancellable (activity);
+ outbox_folder = e_mail_local_get_folder (E_MAIL_FOLDER_OUTBOX);
+
+ info = camel_message_info_new (NULL);
+ camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, ~0);
+
+ e_mail_folder_append_message (
+ outbox_folder, message, info,
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) composer_send_appended,
+ context);
+
+ camel_message_info_free (info);
+}
static void
composer_set_no_change (EMsgComposer *composer)
@@ -588,172 +588,211 @@ composer_set_no_change (EMsgComposer *composer)
}
static void
-save_draft_done (CamelFolder *folder, CamelMimeMessage *msg, CamelMessageInfo *info, gint ok,
- const gchar *appended_uid, gpointer user_data)
+composer_save_draft_complete (EMailSession *session,
+ GAsyncResult *result,
+ AsyncContext *context)
{
- struct _save_draft_info *sdi = user_data;
- struct emcs_t *emcs;
+ GError *error = NULL;
- if (!ok)
- goto done;
+ /* We don't really care if this failed. If something other than
+ * cancellation happened, emit a runtime warning so the error is
+ * not completely lost. */
- if ((emcs = sdi->emcs) == NULL)
- emcs = emcs_new ();
+ e_mail_session_handle_draft_headers_finish (session, result, &error);
- if (emcs->drafts_folder) {
- /* delete the original draft message */
- camel_folder_set_message_flags (
- emcs->drafts_folder, emcs->drafts_uid,
- CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN,
- CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN);
- g_object_unref (emcs->drafts_folder);
- emcs->drafts_folder = NULL;
- g_free (emcs->drafts_uid);
- emcs->drafts_uid = NULL;
- }
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_error_free (error);
- if (emcs->folder) {
- /* set the replied flags etc */
- camel_folder_set_message_flags (
- emcs->folder, emcs->uid,
- emcs->flags, emcs->set);
- g_object_unref (emcs->folder);
- emcs->folder = NULL;
- g_free (emcs->uid);
- emcs->uid = NULL;
+ else if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
}
- if (appended_uid) {
- g_object_ref (folder);
- emcs->drafts_folder = folder;
- emcs->drafts_uid = g_strdup (appended_uid);
- }
+ /* Encode the draft message we just saved into the EMsgComposer
+ * as X-Evolution-Draft headers. The message will be marked for
+ * deletion if the user saves a newer draft message or sends the
+ * composed message. */
+ e_msg_composer_set_draft_headers (
+ context->composer, context->folder_uri,
+ context->message_uid);
- if (e_msg_composer_is_exiting (sdi->composer))
- gtk_widget_destroy (GTK_WIDGET (sdi->composer));
+ e_activity_complete (context->activity);
- done:
- g_object_unref (sdi->composer);
- if (sdi->emcs)
- emcs_unref (sdi->emcs);
- camel_message_info_free (info);
- g_free (sdi);
+ async_context_free (context);
}
static void
-save_draft_folder (gchar *uri, CamelFolder *folder, gpointer data)
+composer_save_draft_cleanup (CamelFolder *drafts_folder,
+ GAsyncResult *result,
+ AsyncContext *context)
{
- CamelFolder **save = data;
+ CamelSession *session;
+ GCancellable *cancellable;
+ GError *error = NULL;
+
+ e_mail_folder_append_message_finish (
+ drafts_folder, result, &context->message_uid, &error);
+
+ /* Ignore cancellations. */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_warn_if_fail (context->message_uid == NULL);
+ async_context_free (context);
+ g_error_free (error);
+ return;
+ }
- if (folder) {
- *save = folder;
- g_object_ref (folder);
+ if (error != NULL) {
+ g_warn_if_fail (context->message_uid == NULL);
+ e_alert_submit (
+ GTK_WIDGET (context->composer),
+ "mail-composer:save-draft-error",
+ error->message, NULL);
+ async_context_free (context);
+ g_error_free (error);
+ return;
}
+
+ session = e_msg_composer_get_session (context->composer);
+ cancellable = e_activity_get_cancellable (context->activity);
+
+ /* Mark the previously saved draft message for deletion.
+ * Note: This is just a nice-to-have; ignore failures. */
+ e_mail_session_handle_draft_headers (
+ E_MAIL_SESSION (session), context->message,
+ G_PRIORITY_DEFAULT, cancellable, (GAsyncReadyCallback)
+ composer_save_draft_complete, context);
}
static void
-em_utils_composer_save_draft_cb (EMsgComposer *composer)
+composer_save_draft_append_mail (AsyncContext *context,
+ CamelFolder *drafts_folder)
{
CamelFolder *local_drafts_folder;
- EComposerHeaderTable *table;
- struct _save_draft_info *sdi;
- const gchar *local_drafts_folder_uri;
- CamelFolder *folder = NULL;
- CamelMimeMessage *msg;
+ GCancellable *cancellable;
CamelMessageInfo *info;
- CamelSession *session;
- 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
- * down, waiting for the folder to open */
-
- session = e_msg_composer_get_session (composer);
local_drafts_folder =
e_mail_local_get_folder (E_MAIL_FOLDER_DRAFTS);
- local_drafts_folder_uri =
- e_mail_local_get_folder_uri (E_MAIL_FOLDER_DRAFTS);
- msg = e_msg_composer_get_message_draft (composer, NULL, &error);
+ if (drafts_folder == NULL)
+ drafts_folder = g_object_ref (local_drafts_folder);
+
+ cancellable = e_activity_get_cancellable (context->activity);
+
+ info = camel_message_info_new (NULL);
+
+ camel_message_info_set_flags (
+ info, CAMEL_MESSAGE_DRAFT | CAMEL_MESSAGE_SEEN, ~0);
+
+ e_mail_folder_append_message (
+ drafts_folder, context->message,
+ info, G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) composer_save_draft_cleanup,
+ context);
+
+ camel_message_info_free (info);
+
+ g_object_unref (drafts_folder);
+}
+
+static void
+composer_save_draft_got_folder (EMailSession *session,
+ GAsyncResult *result,
+ AsyncContext *context)
+{
+ CamelFolder *drafts_folder;
+ GError *error = NULL;
+
+ drafts_folder = e_mail_session_uri_to_folder_finish (
+ session, result, &error);
/* Ignore cancellations. */
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
- g_warn_if_fail (msg == NULL);
+ g_warn_if_fail (drafts_folder == NULL);
+ async_context_free (context);
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);
+ gint response;
+
+ g_warn_if_fail (drafts_folder == NULL);
+
+ /* XXX Not showing the error message in the dialog? */
g_error_free (error);
- return;
+
+ /* If we can't retrieve the Drafts folder for the
+ * selected account, ask the user if he wants to
+ * save to the local Drafts folder instead. */
+ response = e_alert_run_dialog_for_args (
+ GTK_WINDOW (context->composer),
+ "mail:ask-default-drafts", NULL);
+ if (response != GTK_RESPONSE_YES) {
+ async_context_free (context);
+ return;
+ }
}
- g_return_if_fail (CAMEL_IS_MIME_MESSAGE (msg));
+ composer_save_draft_append_mail (context, drafts_folder);
+}
+
+static void
+em_utils_composer_save_draft_cb (EMsgComposer *composer,
+ CamelMimeMessage *message,
+ EActivity *activity)
+{
+ AsyncContext *context;
+ EComposerHeaderTable *table;
+ const gchar *drafts_folder_uri = NULL;
+ const gchar *local_drafts_folder_uri;
+ CamelSession *session;
+ EAccount *account;
+
+ context = g_slice_new0 (AsyncContext);
+ context->message = g_object_ref (message);
+ context->composer = g_object_ref (composer);
+ context->activity = g_object_ref (activity);
+
+ session = e_msg_composer_get_session (composer);
+
+ local_drafts_folder_uri =
+ e_mail_local_get_folder_uri (E_MAIL_FOLDER_DRAFTS);
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 = g_object_ref (composer);
- sdi->emcs = g_object_get_data (G_OBJECT (composer), "emcs");
- if (sdi->emcs)
- emcs_ref (sdi->emcs);
+ if (account != NULL && account->enabled)
+ drafts_folder_uri = account->drafts_folder_uri;
- if (account && account->drafts_folder_uri &&
- strcmp (account->drafts_folder_uri, local_drafts_folder_uri) != 0) {
- gint id;
+ if (g_strcmp0 (drafts_folder_uri, local_drafts_folder_uri) == 0)
+ drafts_folder_uri = NULL;
- id = mail_get_folder (
- E_MAIL_SESSION (session),
- account->drafts_folder_uri, 0,
- save_draft_folder, &folder,
- mail_msg_unordered_push);
- mail_msg_wait (id);
-
- if (!folder || !account->enabled) {
- if (e_alert_run_dialog_for_args ((GtkWindow *)composer, "mail:ask-default-drafts", NULL) != GTK_RESPONSE_YES) {
- g_object_unref (composer);
- g_object_unref (msg);
- if (sdi->emcs)
- emcs_unref (sdi->emcs);
- g_free (sdi);
- return;
- }
-
- folder = local_drafts_folder;
- g_object_ref (local_drafts_folder);
- }
+ if (drafts_folder_uri == NULL) {
+ composer_save_draft_append_mail (context, NULL);
+ context->folder_uri = g_strdup (local_drafts_folder_uri);
} else {
- folder = local_drafts_folder;
- g_object_ref (folder);
- }
-
- info = camel_message_info_new (NULL);
+ GCancellable *cancellable;
- camel_message_info_set_flags (
- info, CAMEL_MESSAGE_DRAFT | CAMEL_MESSAGE_SEEN, ~0);
+ cancellable = e_activity_get_cancellable (activity);
+ context->folder_uri = g_strdup (drafts_folder_uri);
- mail_append_mail (folder, msg, info, save_draft_done, sdi);
- g_object_unref (folder);
- g_object_unref (msg);
+ e_mail_session_uri_to_folder (
+ E_MAIL_SESSION (session),
+ drafts_folder_uri, 0, G_PRIORITY_DEFAULT,
+ cancellable, (GAsyncReadyCallback)
+ composer_save_draft_got_folder, context);
+ }
}
static void
em_utils_composer_print_cb (EMsgComposer *composer,
- GtkPrintOperationAction action)
+ GtkPrintOperationAction action,
+ CamelMimeMessage *message,
+ EActivity *activity)
{
- CamelMimeMessage *message;
EMFormatHTMLPrint *efhp;
- message = e_msg_composer_get_message_print (composer, 1, NULL);
-
efhp = em_format_html_print_new (NULL, action);
em_format_html_print_raw_message (efhp, message);
g_object_unref (efhp);
@@ -998,14 +1037,14 @@ traverse_parts (GSList *clues, CamelMimeMessage *message, CamelDataWrapper *cont
static GtkWidget *
edit_message (EShell *shell,
+ CamelFolder *folder,
CamelMimeMessage *message,
- CamelFolder *drafts,
- const gchar *uid)
+ const gchar *message_uid)
{
EMsgComposer *composer;
/* Template specific code follows. */
- if (em_utils_folder_is_templates (drafts, NULL) == TRUE) {
+ if (em_utils_folder_is_templates (folder, NULL)) {
GConfClient *gconf;
GSList *clue_list = NULL;
@@ -1022,11 +1061,14 @@ edit_message (EShell *shell,
composer = e_msg_composer_new_with_message (shell, message, NULL);
- if (em_utils_folder_is_drafts (drafts, NULL)) {
- struct emcs_t *emcs;
+ if (message_uid != NULL) {
+ const gchar *folder_uri;
+
+ folder_uri = camel_folder_get_uri (folder);
- emcs = g_object_get_data (G_OBJECT (composer), "emcs");
- emcs_set_drafts_info (emcs, drafts, uid);
+ if (em_utils_folder_is_drafts (folder, folder_uri))
+ e_msg_composer_set_draft_headers (
+ composer, folder_uri, message_uid);
}
composer_set_no_change (composer);
@@ -1039,21 +1081,22 @@ edit_message (EShell *shell,
/**
* em_utils_edit_message:
* @shell: an #EShell
- * @message: message to edit
- * @folder: used to recognize the templates folder
+ * @folder: a #CamelFolder
+ * @message: a #CamelMimeMessage
*
* Opens a composer filled in with the headers/mime-parts/etc of
* @message.
**/
GtkWidget *
em_utils_edit_message (EShell *shell,
- CamelMimeMessage *message,
- CamelFolder *folder)
+ CamelFolder *folder,
+ CamelMimeMessage *message)
{
g_return_val_if_fail (E_IS_SHELL (shell), NULL);
+ g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
- return edit_message (shell, message, folder, NULL);
+ return edit_message (shell, folder, message, NULL);
}
static void
@@ -1071,7 +1114,7 @@ edit_messages_replace (CamelFolder *folder,
for (ii = 0; ii < msgs->len; ii++) {
camel_medium_remove_header (
CAMEL_MEDIUM (msgs->pdata[ii]), "X-Mailer");
- edit_message (shell, msgs->pdata[ii], folder, uids->pdata[ii]);
+ edit_message (shell, folder, msgs->pdata[ii], uids->pdata[ii]);
}
g_object_unref (shell);
@@ -1092,7 +1135,7 @@ edit_messages_no_replace (CamelFolder *folder,
for (ii = 0; ii < msgs->len; ii++) {
camel_medium_remove_header (
CAMEL_MEDIUM (msgs->pdata[ii]), "X-Mailer");
- edit_message (shell, msgs->pdata[ii], NULL, NULL);
+ edit_message (shell, NULL, msgs->pdata[ii], NULL);
}
g_object_unref (shell);
@@ -1300,6 +1343,7 @@ forward_non_attached (EShell *shell,
{
CamelMimeMessage *message;
EMsgComposer *composer = NULL;
+ const gchar *folder_uri;
gchar *subject, *text;
gint i;
guint32 flags;
@@ -1307,6 +1351,8 @@ forward_non_attached (EShell *shell,
if (messages->len == 0)
return NULL;
+ folder_uri = camel_folder_get_uri (folder);
+
flags = EM_FORMAT_QUOTE_HEADERS | EM_FORMAT_QUOTE_KEEP_SIG;
if (style == MAIL_CONFIG_FORWARD_QUOTED)
flags |= EM_FORMAT_QUOTE_CITE;
@@ -1329,12 +1375,11 @@ forward_non_attached (EShell *shell,
e_msg_composer_set_body_text (composer, text, len);
- if (uids && uids->pdata[i]) {
- struct emcs_t *emcs;
-
- emcs = g_object_get_data (G_OBJECT (composer), "emcs");
- emcs_set_folder_info (emcs, folder, uids->pdata[i], CAMEL_MESSAGE_FORWARDED, CAMEL_MESSAGE_FORWARDED);
- }
+ if (uids && uids->pdata[i])
+ e_msg_composer_set_source_headers (
+ composer, folder_uri,
+ uids->pdata[i],
+ CAMEL_MESSAGE_FORWARDED);
emu_update_composers_security (composer, validity_found);
composer_set_no_change (composer);
@@ -2533,7 +2578,6 @@ em_utils_reply_to_message (EShell *shell,
EMsgComposer *composer;
EAccount *account;
guint32 flags;
- struct emcs_t *emcs;
g_return_val_if_fail (E_IS_SHELL (shell), NULL);
@@ -2599,8 +2643,15 @@ em_utils_reply_to_message (EShell *shell,
composer_set_body (composer, message, source);
g_object_unref (message);
- emcs = g_object_get_data (G_OBJECT (composer), "emcs");
- emcs_set_folder_info (emcs, folder, uid, flags, flags);
+
+ if (folder != NULL) {
+ const gchar *folder_uri;
+
+ folder_uri = camel_folder_get_uri (folder);
+
+ e_msg_composer_set_source_headers (
+ composer, folder_uri, uid, flags);
+ }
composer_set_no_change (composer);
@@ -2679,7 +2730,6 @@ em_configure_new_composer (EMsgComposer *composer)
EComposerHeaderTable *table;
EComposerHeaderType header_type;
EComposerHeader *header;
- struct emcs_t *emcs;
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
@@ -2687,11 +2737,29 @@ em_configure_new_composer (EMsgComposer *composer)
table = e_msg_composer_get_header_table (composer);
header = e_composer_header_table_get_header (table, header_type);
- emcs = emcs_new ();
+ g_signal_connect (
+ composer, "presend",
+ G_CALLBACK (composer_presend_check_recipients), NULL);
- g_object_set_data_full (
- G_OBJECT (composer), "emcs", emcs,
- (GDestroyNotify) emcs_unref);
+ g_signal_connect (
+ composer, "presend",
+ G_CALLBACK (composer_presend_check_account), NULL);
+
+ g_signal_connect (
+ composer, "presend",
+ G_CALLBACK (composer_presend_check_downloads), NULL);
+
+ g_signal_connect (
+ composer, "presend",
+ G_CALLBACK (composer_presend_check_plugins), NULL);
+
+ g_signal_connect (
+ composer, "presend",
+ G_CALLBACK (composer_presend_check_subject), NULL);
+
+ g_signal_connect (
+ composer, "presend",
+ G_CALLBACK (composer_presend_check_unwanted_html), NULL);
g_signal_connect (
composer, "send",