2007-02-09 [paul] 2.7.2cvs34
[claws.git] / src / compose.c
index 22e98e8ec3f875ae30cd1aec66d472b6cb3c675a..c0d2966c71f7205c79e19465821c438456adfd1e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Claws Mail team
+ * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -81,7 +81,7 @@
 #  include <wctype.h>
 #endif
 
-#include "sylpheed.h"
+#include "claws.h"
 #include "main.h"
 #include "mainwindow.h"
 #include "compose.h"
@@ -171,13 +171,6 @@ typedef enum
        COMPOSE_INSERT_NO_FILE
 } ComposeInsertResult;
 
-typedef enum
-{
-       COMPOSE_QUIT_EDITING,
-       COMPOSE_KEEP_EDITING,
-       COMPOSE_AUTO_SAVE
-} ComposeDraftAction;
-
 typedef enum
 {
        COMPOSE_WRITE_FOR_SEND,
@@ -191,7 +184,7 @@ typedef enum
 
 static GList *compose_list = NULL;
 
-Compose *compose_generic_new                   (PrefsAccount   *account,
+static Compose *compose_generic_new                    (PrefsAccount   *account,
                                                 const gchar    *to,
                                                 FolderItem     *item,
                                                 GPtrArray      *attach_files,
@@ -201,6 +194,27 @@ static Compose *compose_create                     (PrefsAccount   *account,
                                                 ComposeMode     mode,
                                                 gboolean batch);
 
+static void compose_entry_mark_default_to      (Compose          *compose,
+                                        const gchar      *address);
+static Compose *compose_followup_and_reply_to  (MsgInfo        *msginfo,
+                                        gboolean        quote,
+                                        gboolean        to_all,
+                                        gboolean        to_sender,
+                                        const gchar    *body);
+static Compose *compose_forward_multiple       (PrefsAccount   *account, 
+                                        GSList         *msginfo_list);
+static Compose *compose_reply                  (MsgInfo        *msginfo,
+                                        gboolean        quote,
+                                        gboolean        to_all,
+                                        gboolean        to_ml,
+                                        gboolean        to_sender,
+                                        const gchar    *body);
+static Compose *compose_reply_mode             (ComposeMode     mode, 
+                                        GSList         *msginfo_list, 
+                                        gchar          *body);
+static void compose_template_apply_fields(Compose *compose, Template *tmpl);
+static void compose_update_privacy_systems_menu(Compose        *compose);
+
 static GtkWidget *compose_account_option_menu_create
                                                (Compose        *compose);
 static void compose_set_out_encoding           (Compose        *compose);
@@ -223,6 +237,7 @@ static gchar *compose_quote_fmt                     (Compose        *compose,
                                                 const gchar    *qmark,
                                                 const gchar    *body,
                                                 gboolean        rewrap,
+                                                gboolean        need_unescape,
                                                 const gchar *err_msg);
 
 static void compose_reply_set_entry            (Compose        *compose,
@@ -265,7 +280,7 @@ static PrefsAccount *compose_current_mail_account(void);
 static gboolean compose_check_for_valid_recipient
                                                (Compose        *compose);
 static gboolean compose_check_entries          (Compose        *compose,
-                                                gboolean       check_subject);
+                                                gboolean       check_everything);
 static gint compose_write_to_file              (Compose        *compose,
                                                 FILE           *fp,
                                                 gint            action,
@@ -274,7 +289,7 @@ static gint compose_write_body_to_file              (Compose        *compose,
                                                 const gchar    *file);
 static gint compose_remove_reedit_target       (Compose        *compose,
                                                 gboolean        force);
-void compose_remove_draft                      (Compose        *compose);
+static void compose_remove_draft                       (Compose        *compose);
 static gint compose_queue_sub                  (Compose        *compose,
                                                 gint           *msgnum,
                                                 FolderItem     **item,
@@ -450,7 +465,7 @@ static void compose_set_priority_cb (gpointer        data,
                                         guint           action,
                                         GtkWidget      *widget);
 static void compose_reply_change_mode  (gpointer        data,
-                                        guint           action,
+                                        ComposeMode    action,
                                         GtkWidget      *widget);
 
 static void compose_attach_drag_received_cb (GtkWidget         *widget,
@@ -494,9 +509,9 @@ static Compose *compose_generic_reply(MsgInfo *msginfo, gboolean quote,
                                  gboolean followup_and_reply_to,
                                  const gchar *body);
 
-gboolean compose_headerentry_changed_cb           (GtkWidget          *entry,
+static gboolean compose_headerentry_changed_cb    (GtkWidget          *entry,
                                            ComposeHeaderEntry *headerentry);
-gboolean compose_headerentry_key_press_event_cb(GtkWidget             *entry,
+static gboolean compose_headerentry_key_press_event_cb(GtkWidget              *entry,
                                            GdkEventKey        *event,
                                            ComposeHeaderEntry *headerentry);
 
@@ -516,18 +531,23 @@ static PrefsAccount *compose_guess_forward_account_from_msginfo   (MsgInfo *msginf
 
 static MsgInfo *compose_msginfo_new_from_compose(Compose *compose);
 
+#ifdef USE_ASPELL
+static void compose_set_dictionaries_from_folder_prefs(Compose *compose,
+                                               FolderItem *folder_item);
+#endif
+
 static GtkItemFactoryEntry compose_popup_entries[] =
 {
        {N_("/_Add..."),        NULL, compose_attach_cb, 0, NULL},
        {N_("/_Remove"),        NULL, compose_attach_remove_selected, 0, NULL},
-       {N_("/---"),            NULL, NULL, 0, "<Separator>"},
+       {"/---",                NULL, NULL, 0, "<Separator>"},
        {N_("/_Properties..."), NULL, compose_attach_property, 0, NULL}
 };
 
 static GtkItemFactoryEntry compose_entries[] =
 {
        {N_("/_Message"),                               NULL, NULL, 0, "<Branch>"},
-       {N_("/_Message/_Send"),         "<control>Return",
+       {N_("/_Message/S_end"),         "<control>Return",
                                        compose_send_cb, 0, NULL},
        {N_("/_Message/Send _later"),   "<shift><control>S",
                                        compose_send_later_cb,  0, NULL},
@@ -971,11 +991,7 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI
 
        undo_block(compose->undostruct);
 #ifdef USE_ASPELL
-       if (item && item->prefs && item->prefs->enable_default_dictionary &&
-           compose->gtkaspell) 
-               gtkaspell_change_dict(compose->gtkaspell, 
-                   item->prefs->default_dictionary);
-       compose_spell_menu_changed(compose);
+       compose_set_dictionaries_from_folder_prefs(compose, item);
 #endif
 
        if (account->auto_sig)
@@ -1059,7 +1075,7 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI
 
                        compose_quote_fmt(compose, dummyinfo,
                                          prefs_common.compose_body_format,
-                                         NULL, tmp, FALSE,
+                                         NULL, tmp, FALSE, TRUE,
                                                  _("New message body format error."));
                        quote_fmt_reset_vartable();
 
@@ -1124,7 +1140,8 @@ static void compose_force_encryption(Compose *compose, PrefsAccount *account,
                }
        }
        if (privacy != NULL) {
-               compose->privacy_system = g_strdup(privacy);
+               if (compose->privacy_system == NULL)
+                       compose->privacy_system = g_strdup(privacy);
                compose_update_privacy_system_menu_item(compose, FALSE);
                compose_use_encryption(compose, TRUE);
        }
@@ -1144,13 +1161,14 @@ static void compose_force_signing(Compose *compose, PrefsAccount *account)
                }
        }
        if (privacy != NULL) {
-               compose->privacy_system = g_strdup(privacy);
+               if (compose->privacy_system == NULL)
+                       compose->privacy_system = g_strdup(privacy);
                compose_update_privacy_system_menu_item(compose, FALSE);
                compose_use_signing(compose, TRUE);
        }
 }      
 
-Compose *compose_reply_mode(ComposeMode mode, GSList *msginfo_list, gchar *body)
+static Compose *compose_reply_mode(ComposeMode mode, GSList *msginfo_list, gchar *body)
 {
        MsgInfo *msginfo;
        guint list_len;
@@ -1280,7 +1298,7 @@ Compose *compose_reply_mode(ComposeMode mode, GSList *msginfo_list, gchar *body)
        return compose;
 }
 
-Compose *compose_reply(MsgInfo *msginfo, gboolean quote, gboolean to_all,
+static Compose *compose_reply(MsgInfo *msginfo, gboolean quote, gboolean to_all,
                   gboolean to_ml, gboolean to_sender, 
                   const gchar *body)
 {
@@ -1288,7 +1306,7 @@ Compose *compose_reply(MsgInfo *msginfo, gboolean quote, gboolean to_all,
                              to_sender, FALSE, body);
 }
 
-Compose *compose_followup_and_reply_to(MsgInfo *msginfo, gboolean quote,
+static Compose *compose_followup_and_reply_to(MsgInfo *msginfo, gboolean quote,
                                   gboolean to_all,
                                   gboolean to_sender,
                                   const gchar *body)
@@ -1356,7 +1374,7 @@ static Compose *compose_generic_reply(MsgInfo *msginfo, gboolean quote,
        g_return_val_if_fail(msginfo->folder != NULL, NULL);
 
        account = account_get_reply_account(msginfo, prefs_common.reply_account_autosel);
-       
+
        g_return_val_if_fail(account != NULL, NULL);
 
        if (to_sender && account->protocol == A_NNTP &&
@@ -1406,12 +1424,7 @@ static Compose *compose_generic_reply(MsgInfo *msginfo, gboolean quote,
 
        undo_block(compose->undostruct);
 #ifdef USE_ASPELL
-       if (msginfo->folder && msginfo->folder->prefs && 
-           msginfo->folder->prefs && 
-           msginfo->folder->prefs->enable_default_dictionary &&
-           compose->gtkaspell)
-               gtkaspell_change_dict(compose->gtkaspell, 
-                   msginfo->folder->prefs->default_dictionary);
+               compose_set_dictionaries_from_folder_prefs(compose, msginfo->folder);
 #endif
 
        if (quote) {
@@ -1424,7 +1437,7 @@ static Compose *compose_generic_reply(MsgInfo *msginfo, gboolean quote,
 
                compose_quote_fmt(compose, compose->replyinfo,
                                  prefs_common.quotefmt,
-                                 qmark, body, FALSE,
+                                 qmark, body, FALSE, TRUE,
                                          _("Message reply format error."));
                quote_fmt_reset_vartable();
        }
@@ -1541,7 +1554,7 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
 
                compose_quote_fmt(compose, full_msginfo,
                                  prefs_common.fw_quotefmt,
-                                 qmark, body, FALSE,
+                                 qmark, body, FALSE, TRUE,
                                          _("Message forward format error."));
                quote_fmt_reset_vartable();
                compose_attach_parts(compose, msginfo);
@@ -1593,7 +1606,7 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
 
 #undef INSERT_FW_HEADER
 
-Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
+static Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
 {
        Compose *compose;
        GtkTextView *textview;
@@ -1768,6 +1781,11 @@ Compose *compose_reedit(MsgInfo *msginfo, gboolean batch)
                gint id, param;
 
                /* Select Account from queue headers */
+               if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
+                                            sizeof(queueheader_buf), "X-Claws-Account-Id:")) {
+                       id = atoi(&queueheader_buf[strlen("X-Claws-Account-Id:")]);
+                       account = account_find_from_id(id);
+               }
                if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
                                             sizeof(queueheader_buf), "X-Sylpheed-Account-Id:")) {
                        id = atoi(&queueheader_buf[strlen("X-Sylpheed-Account-Id:")]);
@@ -1787,17 +1805,32 @@ Compose *compose_reedit(MsgInfo *msginfo, gboolean batch)
                                                                sizeof(queueheader_buf), "S:")) {
                        account = account_find_from_address(queueheader_buf);
                }
+               if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
+                                            sizeof(queueheader_buf), "X-Claws-Sign:")) {
+                       param = atoi(&queueheader_buf[strlen("X-Claws-Sign:")]);
+                       use_signing = param;
+                       
+               }
                if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
                                             sizeof(queueheader_buf), "X-Sylpheed-Sign:")) {
                        param = atoi(&queueheader_buf[strlen("X-Sylpheed-Sign:")]);
                        use_signing = param;
                        
                }
+               if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
+                                            sizeof(queueheader_buf), "X-Claws-Encrypt:")) {
+                       param = atoi(&queueheader_buf[strlen("X-Claws-Encrypt:")]);
+                       use_encryption = param;
+               }
                if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
                                             sizeof(queueheader_buf), "X-Sylpheed-Encrypt:")) {
                        param = atoi(&queueheader_buf[strlen("X-Sylpheed-Encrypt:")]);
                        use_encryption = param;
                }
+                if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
+                                            sizeof(queueheader_buf), "X-Claws-Privacy-System:")) {
+                        privacy_system = g_strdup(&queueheader_buf[strlen("X-Claws-Privacy-System:")]);
+                }
                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
                                             sizeof(queueheader_buf), "X-Sylpheed-Privacy-System:")) {
                         privacy_system = g_strdup(&queueheader_buf[strlen("X-Sylpheed-Privacy-System:")]);
@@ -2016,7 +2049,7 @@ Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo,
                                   msginfo->subject);
        gtk_editable_set_editable(GTK_EDITABLE(compose->subject_entry), FALSE);
 
-       compose_quote_fmt(compose, msginfo, "%M", NULL, NULL, FALSE,
+       compose_quote_fmt(compose, msginfo, "%M", NULL, NULL, FALSE, FALSE,
                                          _("Message redirect format error."));
        quote_fmt_reset_vartable();
        gtk_text_view_set_editable(GTK_TEXT_VIEW(compose->text), FALSE);
@@ -2135,7 +2168,7 @@ void compose_entry_append(Compose *compose, const gchar *address,
        }
 }
 
-void compose_entry_mark_default_to(Compose *compose, const gchar *mailto)
+static void compose_entry_mark_default_to(Compose *compose, const gchar *mailto)
 {
        static GdkColor yellow;
        static GdkColor black;
@@ -2223,7 +2256,7 @@ static void compose_entries_set(Compose *compose, const gchar *mailto)
        gchar *subject = NULL;
        gchar *body = NULL;
        gchar *temp = NULL;
-       guint  len = 0;
+       gsize  len = 0;
        gchar *attach = NULL;
        
        scan_mailto_url(mailto, &to, &cc, NULL, &subject, &body, &attach);
@@ -2477,6 +2510,7 @@ static gchar *compose_parse_references(const gchar *ref, const gchar *msgid)
 static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
                                const gchar *fmt, const gchar *qmark,
                                const gchar *body, gboolean rewrap,
+                               gboolean need_unescape,
                                const gchar *err_msg)
 {
        MsgInfo* dummyinfo = NULL;
@@ -2511,20 +2545,25 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
        }
 
        if (fmt && *fmt != '\0') {
-               gchar *tmp = NULL;
 
                if (trimmed_body)
                        while (*trimmed_body == '\n')
                                trimmed_body++;
 
-               /* decode \-escape sequences in the internal representation of the quote format */
-               tmp = malloc(strlen(fmt)+1);
-               pref_get_unescaped_pref(tmp, fmt);
-
                quote_fmt_init(msginfo, quote_str, trimmed_body, FALSE, compose->account);
-               quote_fmt_scan_string(tmp);
-               quote_fmt_parse();
-               g_free(tmp);
+               if (need_unescape) {
+                       gchar *tmp = NULL;
+
+                       /* decode \-escape sequences in the internal representation of the quote format */
+                       tmp = malloc(strlen(fmt)+1);
+                       pref_get_unescaped_pref(tmp, fmt);
+                       quote_fmt_scan_string(tmp);
+                       quote_fmt_parse();
+                       g_free(tmp);
+               } else {
+                       quote_fmt_scan_string(fmt);
+                       quote_fmt_parse();
+               }
 
                buf = quote_fmt_get_buffer();
                if (buf == NULL) {
@@ -2702,13 +2741,21 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
                                          msginfo->from ? msginfo->from : "",
                                          COMPOSE_TO);
                        else if (!to_all && !to_sender) {
-                               /* reply to the last list of recipients */
-                               compose_entry_append(compose,
-                                         msginfo->to ? msginfo->to : "",
-                                         COMPOSE_TO);
-                               compose_entry_append(compose,
-                                         msginfo->cc ? msginfo->cc : "",
-                                         COMPOSE_CC);
+                               if (!folder_has_parent_of_type(msginfo->folder, F_QUEUE) &&
+                                   !folder_has_parent_of_type(msginfo->folder, F_OUTBOX) &&
+                                   !folder_has_parent_of_type(msginfo->folder, F_DRAFT)) {
+                                       compose_entry_append(compose,
+                                                 msginfo->from ? msginfo->from : "",
+                                                 COMPOSE_TO);
+                               } else {
+                                       /* replying to own mail, use original recp */
+                                       compose_entry_append(compose,
+                                                 msginfo->to ? msginfo->to : "",
+                                                 COMPOSE_TO);
+                                       compose_entry_append(compose,
+                                                 msginfo->cc ? msginfo->cc : "",
+                                                 COMPOSE_CC);
+                               }
                        }
                }
        } else {
@@ -2780,17 +2827,17 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
 
        to_table = g_hash_table_new(g_str_hash, g_str_equal);
        if (replyto)
-               g_hash_table_insert(to_table, g_strdup(replyto), GINT_TO_POINTER(1));
-       if (compose->account)
-               g_hash_table_insert(to_table, g_strdup(compose->account->address),
+               g_hash_table_insert(to_table, g_utf8_strdown(replyto, -1), GINT_TO_POINTER(1));
+       if (compose->account) {
+               g_hash_table_insert(to_table, g_utf8_strdown(compose->account->address, -1),
                                    GINT_TO_POINTER(1));
-
+       }
        /* remove address on To: and that of current account */
        for (cur = cc_list; cur != NULL; ) {
                GSList *next = cur->next;
                gchar *addr;
 
-               addr = g_strdup(cur->data);
+               addr = g_utf8_strdown(cur->data, -1);
                extract_address(addr);
 
                if (GPOINTER_TO_INT(g_hash_table_lookup(to_table, addr)) == 1)
@@ -3078,6 +3125,17 @@ static gboolean compose_attach_append(Compose *compose, const gchar *file,
        gboolean has_binary = FALSE;
 
        if (!is_file_exist(file)) {
+               gchar *file_from_uri = g_filename_from_uri(file, NULL, NULL);
+               gboolean result = FALSE;
+               if (file_from_uri && is_file_exist(file_from_uri)) {
+                       result = compose_attach_append(
+                                               compose, file_from_uri,
+                                               filename,
+                                               content_type);
+               }
+               g_free(file_from_uri);
+               if (result)
+                       return TRUE;
                alertpanel_error("File %s doesn't exist\n", filename);
                return FALSE;
        }
@@ -3244,6 +3302,8 @@ static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
      
        child = (MimeInfo *) mimeinfo->node->children->data;
        while (child != NULL) {
+               gint err;
+
                if (child == encrypted) {
                        /* skip this part of tree */
                        NEXT_PART_NOT_CHILD(child);
@@ -3262,8 +3322,8 @@ static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
                }
 
                outfile = procmime_get_tmp_file_name(child);
-               if (procmime_get_part(outfile, child) < 0)
-                       g_warning("Can't get the part of multipart message.");
+               if ((err = procmime_get_part(outfile, child)) < 0)
+                       g_warning("Can't get the part of multipart message. (%s)", strerror(-err));
                else {
                        gchar *content_type;
 
@@ -3271,7 +3331,9 @@ static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
 
                        /* if we meet a pgp signature, we don't attach it, but
                         * we force signing. */
-                       if (strcmp(content_type, "application/pgp-signature")) {
+                       if (strcmp(content_type, "application/pgp-signature") &&
+                           strcmp(content_type, "application/pkcs7-signature") &&
+                           strcmp(content_type, "application/x-pkcs7-signature")) {
                                partname = procmime_mimeinfo_get_parameter(child, "filename");
                                if (partname == NULL)
                                        partname = procmime_mimeinfo_get_parameter(child, "name");
@@ -4076,6 +4138,21 @@ static void compose_select_account(Compose *compose, PrefsAccount *account,
                compose_insert_sig(compose, TRUE);
                undo_unblock(compose->undostruct);
        }
+
+#ifdef USE_ASPELL
+       /* use account's dict info if set */
+       if (compose->gtkaspell) {
+               if (account->enable_default_dictionary)
+                       gtkaspell_change_dict(compose->gtkaspell,
+                                       account->default_dictionary, FALSE);
+               if (account->enable_default_alt_dictionary)
+                       gtkaspell_change_alt_dict(compose->gtkaspell,
+                                       account->default_alt_dictionary);
+               if (account->enable_default_dictionary
+                       || account->enable_default_alt_dictionary)
+                       compose_spell_menu_changed(compose);
+       }
+#endif
 }
 
 gboolean compose_check_for_valid_recipient(Compose *compose) {
@@ -4100,6 +4177,7 @@ gboolean compose_check_for_valid_recipient(Compose *compose) {
                gchar *entry;
                header = gtk_editable_get_chars(GTK_EDITABLE(GTK_COMBO(((ComposeHeaderEntry *)list->data)->combo)->entry), 0, -1);
                entry = gtk_editable_get_chars(GTK_EDITABLE(((ComposeHeaderEntry *)list->data)->entry), 0, -1);
+
                g_strstrip(entry);
                if (entry[0] != '\0') {
                        for (strptr = recipient_headers_mail; *strptr != NULL; strptr++) {
@@ -4188,7 +4266,7 @@ static gboolean compose_check_for_set_recipients(Compose *compose)
        return TRUE;
 }
 
-static gboolean compose_check_entries(Compose *compose, gboolean check_subject)
+static gboolean compose_check_entries(Compose *compose, gboolean check_everything)
 {
        const gchar *str;
 
@@ -4206,7 +4284,8 @@ static gboolean compose_check_entries(Compose *compose, gboolean check_subject)
 
        if (!compose->batch) {
                str = gtk_entry_get_text(GTK_ENTRY(compose->subject_entry));
-               if (*str == '\0' && check_subject == TRUE) {
+               if (*str == '\0' && check_everything == TRUE && 
+                   compose->mode != COMPOSE_REDIRECT) {
                        AlertValue aval;
 
                        aval = alertpanel(_("Send"),
@@ -4217,7 +4296,7 @@ static gboolean compose_check_entries(Compose *compose, gboolean check_subject)
                }
        }
 
-       if (hooks_invoke(COMPOSE_CHECK_BEFORE_SEND_HOOKLIST, compose))
+       if (check_everything && hooks_invoke(COMPOSE_CHECK_BEFORE_SEND_HOOKLIST, compose))
                return FALSE;
 
        return TRUE;
@@ -4233,6 +4312,7 @@ gint compose_send(Compose *compose)
        gchar *errstr = NULL;
        gchar *tmsgid = NULL;
        MainWindow *mainwin = mainwindow_get_mainwindow();
+       gboolean queued_removed = FALSE;
 
        if (prefs_common.send_dialog_mode != SEND_DIALOG_ALWAYS
                        || compose->batch == TRUE)
@@ -4295,10 +4375,10 @@ gint compose_send(Compose *compose)
        }
        if (msgpath == NULL) {
                msgpath = folder_item_fetch_msg(folder, msgnum);
-               val = procmsg_send_message_queue(msgpath, &errstr, folder, msgnum);
+               val = procmsg_send_message_queue(msgpath, &errstr, folder, msgnum, &queued_removed);
                g_free(msgpath);
        } else {
-               val = procmsg_send_message_queue(msgpath, &errstr, folder, msgnum);
+               val = procmsg_send_message_queue(msgpath, &errstr, folder, msgnum, &queued_removed);
                g_unlink(msgpath);
                g_free(msgpath);
        }
@@ -4306,7 +4386,8 @@ gint compose_send(Compose *compose)
                compose->sending = FALSE;
                compose_allow_user_actions (compose, TRUE);
                if (val != 0) {
-                       folder_item_remove_msg(folder, msgnum);
+                       if (!queued_removed)
+                               folder_item_remove_msg(folder, msgnum);
                        folder_item_scan(folder);
                        if (tmsgid) {
                                /* make sure we delete that */
@@ -4321,7 +4402,8 @@ gint compose_send(Compose *compose)
        }
 
        if (val == 0) {
-               folder_item_remove_msg(folder, msgnum);
+               if (!queued_removed)
+                       folder_item_remove_msg(folder, msgnum);
                folder_item_scan(folder);
                if (tmsgid) {
                        /* make sure we delete that */
@@ -4524,8 +4606,10 @@ static gint compose_redirect_write_to_file(Compose *compose, FILE *fdest)
                "SSH:",                 "R:",                   "MAID:",
                "NAID:",                "RMID:",                "FMID:",
                "SCF:",                 "RRCPT:",               "NG:",
+               "X-Claws-Privacy",      "X-Claws-Sign:",        "X-Claws-Encrypt",
+               "X-Claws-End-Special-Headers:",                 "X-Claws-Account-Id:",
                "X-Sylpheed-Privacy",   "X-Sylpheed-Sign:",     "X-Sylpheed-Encrypt",
-               "X-Sylpheed-End-Special-Headers:",
+               "X-Sylpheed-End-Special-Headers:",              "X-Sylpheed-Account-Id:",
                NULL
                };
        if ((fp = g_fopen(compose->redirect_filename, "rb")) == NULL) {
@@ -4872,7 +4956,7 @@ static gint compose_remove_reedit_target(Compose *compose, gboolean force)
        return 0;
 }
 
-void compose_remove_draft(Compose *compose)
+static void compose_remove_draft(Compose *compose)
 {
        FolderItem *drafts;
        MsgInfo *msginfo = compose->targetinfo;
@@ -5005,8 +5089,8 @@ static gint compose_queue_sub(Compose *compose, gint *msgnum, FolderItem **item,
 
        
        if (compose->privacy_system != NULL) {
-               fprintf(fp, "X-Sylpheed-Privacy-System:%s\n", compose->privacy_system);
-               fprintf(fp, "X-Sylpheed-Sign:%d\n", compose->use_signing);
+               fprintf(fp, "X-Claws-Privacy-System:%s\n", compose->privacy_system);
+               fprintf(fp, "X-Claws-Sign:%d\n", compose->use_signing);
                if (compose->use_encryption) {
                        gchar *encdata;
                        if (mailac && mailac->encrypt_to_self) {
@@ -5019,12 +5103,12 @@ static gint compose_queue_sub(Compose *compose, gint *msgnum, FolderItem **item,
                        }
                        if (encdata != NULL) {
                                if (strcmp(encdata, "_DONT_ENCRYPT_")) {
-                                       fprintf(fp, "X-Sylpheed-Encrypt:%d\n", compose->use_encryption);
-                                       fprintf(fp, "X-Sylpheed-Encrypt-Data:%s\n", 
+                                       fprintf(fp, "X-Claws-Encrypt:%d\n", compose->use_encryption);
+                                       fprintf(fp, "X-Claws-Encrypt-Data:%s\n", 
                                                encdata);
                                } /* else we finally dont want to encrypt */
                        } else {
-                               fprintf(fp, "X-Sylpheed-Encrypt:%d\n", compose->use_encryption);
+                               fprintf(fp, "X-Claws-Encrypt:%d\n", compose->use_encryption);
                                /* and if encdata was null, it means there's been a problem in 
                                 * key selection */
                                lock = FALSE;
@@ -5067,7 +5151,7 @@ static gint compose_queue_sub(Compose *compose, gint *msgnum, FolderItem **item,
        }
 
        /* end of headers */
-       fprintf(fp, "X-Sylpheed-End-Special-Headers: 1\n");
+       fprintf(fp, "X-Claws-End-Special-Headers: 1\n");
 
        if (compose->redirect_filename != NULL) {
                if (compose_redirect_write_to_file(compose, fp) < 0) {
@@ -5727,7 +5811,7 @@ static GtkWidget *compose_create_header(Compose *compose)
        return header_scrolledwin ;
 }
 
-GtkWidget *compose_create_attach(Compose *compose)
+static GtkWidget *compose_create_attach(Compose *compose)
 {
        GtkWidget *attach_scrwin;
        GtkWidget *attach_clist;
@@ -6071,7 +6155,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode,
 
        compose->tooltips = gtk_tooltips_new();
 
-       window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+       window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "compose");
        gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
        gtk_widget_set_size_request(window, -1, prefs_common.compose_height);
 
@@ -6150,7 +6234,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode,
        gtk_box_pack_start(GTK_BOX(subject_hbox), subject_frame, TRUE, TRUE, 0);
        gtk_widget_show(subject_frame);
 
-       subject = gtk_hbox_new(FALSE, 0);
+       subject = gtk_hbox_new(FALSE, HSPACING_NARROW);
        gtk_container_set_border_width(GTK_CONTAINER(subject), 0);
        gtk_widget_show(subject);
 
@@ -6333,11 +6417,13 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode,
                    strcmp(prefs_common.dictionary, "")) {
                        gtkaspell = gtkaspell_new(prefs_common.aspell_path,
                                                  prefs_common.dictionary,
+                                                 prefs_common.alt_dictionary,
                                                  conv_get_locale_charset_str(),
                                                  prefs_common.misspelled_col,
                                                  prefs_common.check_while_typing,
                                                  prefs_common.recheck_when_changing_dict,
                                                  prefs_common.use_alternate,
+                                                 prefs_common.use_both_dicts,
                                                  GTK_TEXT_VIEW(text),
                                                  GTK_WINDOW(compose->window),
                                                  compose_spell_menu_changed,
@@ -6511,8 +6597,7 @@ static void compose_reply_change_mode(gpointer data,
        gboolean was_modified = compose->modified;
 
        gboolean all = FALSE, ml = FALSE, sender = FALSE, followup = FALSE;
-       if (compose->mode != COMPOSE_REPLY)
-               return;
+       
        g_return_if_fail(compose->replyinfo != NULL);
        
        if (action == COMPOSE_REPLY && prefs_common.default_reply_list)
@@ -6528,6 +6613,14 @@ static void compose_reply_change_mode(gpointer data,
 
        compose_remove_header_entries(compose);
        compose_reply_set_entry(compose, compose->replyinfo, all, ml, sender, followup);
+       if (compose->account->set_autocc && compose->account->auto_cc)
+               compose_entry_append(compose, compose->account->auto_cc, COMPOSE_CC);
+
+       if (compose->account->set_autobcc && compose->account->auto_bcc) 
+               compose_entry_append(compose, compose->account->auto_bcc, COMPOSE_BCC);
+       
+       if (compose->account->set_autoreplyto && compose->account->auto_replyto)
+               compose_entry_append(compose, compose->account->auto_replyto, COMPOSE_REPLYTO);
        compose_show_first_last_header(compose, TRUE);
        compose->modified = was_modified;
        compose_set_title(compose);
@@ -6723,7 +6816,7 @@ void compose_update_actions_menu(Compose *compose)
        action_update_compose_menu(ifactory, "/Tools/Actions", compose);
 }
 
-void compose_update_privacy_systems_menu(Compose *compose)
+static void compose_update_privacy_systems_menu(Compose *compose)
 {
        static gchar *branch_path = "/Options/Privacy System";
        GtkItemFactory *ifactory;
@@ -6826,7 +6919,7 @@ static void compose_template_apply(Compose *compose, Template *tmpl,
                        gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
 
                        parsed_str = compose_quote_fmt(compose, compose->replyinfo,
-                                                  tmpl->value, qmark, NULL, FALSE, err_msg);
+                                                  tmpl->value, qmark, NULL, FALSE, FALSE, err_msg);
 
                } else if (compose->fwdinfo != NULL) {
 
@@ -6836,7 +6929,7 @@ static void compose_template_apply(Compose *compose, Template *tmpl,
                        gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
 
                        parsed_str = compose_quote_fmt(compose, compose->fwdinfo,
-                                                  tmpl->value, qmark, NULL, FALSE, err_msg);
+                                                  tmpl->value, qmark, NULL, FALSE, FALSE, err_msg);
 
                } else {
                        MsgInfo* dummyinfo = compose_msginfo_new_from_compose(compose);
@@ -6853,7 +6946,7 @@ static void compose_template_apply(Compose *compose, Template *tmpl,
                                gtk_text_buffer_set_text(buffer, "", -1);
 
                        parsed_str = compose_quote_fmt(compose, dummyinfo,
-                                                          tmpl->value, qmark, tmp, FALSE, err_msg);
+                                                          tmpl->value, qmark, tmp, FALSE, FALSE, err_msg);
                        procmsg_msginfo_free( dummyinfo );
 
                        g_free( tmp );
@@ -6890,7 +6983,7 @@ static void compose_template_apply(Compose *compose, Template *tmpl,
        compose_changed_cb(NULL, compose);
 }
 
-void compose_template_apply_fields(Compose *compose, Template *tmpl)
+static void compose_template_apply_fields(Compose *compose, Template *tmpl)
 {
        MsgInfo* dummyinfo = NULL;
        MsgInfo *msginfo = NULL;
@@ -6912,7 +7005,7 @@ void compose_template_apply_fields(Compose *compose, Template *tmpl)
 
                buf = quote_fmt_get_buffer();
                if (buf == NULL) {
-                       alertpanel_error(_("Message To format error."));
+                       alertpanel_error(_("Template To format error."));
                } else {
                        compose_entry_append(compose, buf, COMPOSE_TO);
                }
@@ -6925,7 +7018,7 @@ void compose_template_apply_fields(Compose *compose, Template *tmpl)
 
                buf = quote_fmt_get_buffer();
                if (buf == NULL) {
-                       alertpanel_error(_("Message Cc format error."));
+                       alertpanel_error(_("Template Cc format error."));
                } else {
                        compose_entry_append(compose, buf, COMPOSE_CC);
                }
@@ -6938,7 +7031,7 @@ void compose_template_apply_fields(Compose *compose, Template *tmpl)
 
                buf = quote_fmt_get_buffer();
                if (buf == NULL) {
-                       alertpanel_error(_("Message Bcc format error."));
+                       alertpanel_error(_("Template Bcc format error."));
                } else {
                        compose_entry_append(compose, buf, COMPOSE_BCC);
                }
@@ -6952,7 +7045,7 @@ void compose_template_apply_fields(Compose *compose, Template *tmpl)
 
                buf = quote_fmt_get_buffer();
                if (buf == NULL) {
-                       alertpanel_error(_("Message subject format error."));
+                       alertpanel_error(_("Template subject format error."));
                } else {
                        gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf);
                }
@@ -7261,7 +7354,7 @@ static void compose_attach_property_create(gboolean *cancelled)
 
        debug_print("Creating attach_property window...\n");
 
-       window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+       window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "compose_attach_property");
        gtk_widget_set_size_request(window, 480, -1);
        gtk_container_set_border_width(GTK_CONTAINER(window), 8);
        gtk_window_set_title(GTK_WINDOW(window), _("Properties"));
@@ -7847,7 +7940,7 @@ static void compose_send_cb(gpointer data, guint action, GtkWidget *widget)
                return;
        
        if (compose->draft_timeout_tag != -1) { /* CLAWS: disable draft timeout */
-               gtk_timeout_remove(compose->draft_timeout_tag);
+               g_source_remove(compose->draft_timeout_tag);
                compose->draft_timeout_tag = -1;
        }
 
@@ -7884,9 +7977,62 @@ static void compose_send_later_cb(gpointer data, guint action,
        toolbar_main_set_sensitive(mainwindow_get_mainwindow());
 }
 
-void compose_draft (gpointer data) 
+void compose_draft (gpointer data, guint action) 
+{
+       compose_draft_cb(data, action, NULL);   
+}
+
+#define DRAFTED_AT_EXIT "drafted_at_exit"
+void compose_clear_exit_drafts(void)
 {
-       compose_draft_cb(data, COMPOSE_QUIT_EDITING, NULL);     
+       gchar *filepath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                                     DRAFTED_AT_EXIT, NULL);
+       if (is_file_exist(filepath))
+               g_unlink(filepath);
+       
+       g_free(filepath);
+}
+
+static void compose_register_draft(MsgInfo *info)
+{
+       gchar *filepath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                                     DRAFTED_AT_EXIT, NULL);
+       FILE *fp = fopen(filepath, "ab");
+       
+       if (fp) {
+               fprintf(fp, "%s\t%d\n", folder_item_get_identifier(info->folder), 
+                               info->msgnum);
+               fclose(fp);
+       }
+               
+       g_free(filepath);       
+}
+
+void compose_reopen_exit_drafts(void)
+{
+       gchar *filepath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                                     DRAFTED_AT_EXIT, NULL);
+       FILE *fp = fopen(filepath, "rb");
+       gchar buf[1024];
+       
+       if (fp) {
+               while (fgets(buf, sizeof(buf), fp)) {
+                       gchar **parts = g_strsplit(buf, "\t", 2);
+                       const gchar *folder = parts[0];
+                       int msgnum = parts[1] ? atoi(parts[1]):-1;
+                       
+                       if (folder && *folder && msgnum > -1) {
+                               FolderItem *item = folder_find_item_from_identifier(folder);
+                               MsgInfo *info = folder_item_get_msginfo(item, msgnum);
+                               if (info)
+                                       compose_reedit(info, FALSE);
+                       }
+                       g_strfreev(parts);
+               }       
+               fclose(fp);
+       }       
+       g_free(filepath);
+       compose_clear_exit_drafts();
 }
 
 static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
@@ -7931,7 +8077,7 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
        }
 
        /* Save draft infos */
-       fprintf(fp, "X-Sylpheed-Account-Id:%d\n", compose->account->account_id);
+       fprintf(fp, "X-Claws-Account-Id:%d\n", compose->account->account_id);
        fprintf(fp, "S:%s\n", compose->account->address);
 
        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn))) {
@@ -7945,9 +8091,9 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                fprintf(fp, "RRCPT:1\n");
        }
        if (compose->privacy_system) {
-               fprintf(fp, "X-Sylpheed-Sign:%d\n", compose->use_signing);
-               fprintf(fp, "X-Sylpheed-Encrypt:%d\n", compose->use_encryption);
-               fprintf(fp, "X-Sylpheed-Privacy-System:%s\n", compose->privacy_system);
+               fprintf(fp, "X-Claws-Sign:%d\n", compose->use_signing);
+               fprintf(fp, "X-Claws-Encrypt:%d\n", compose->use_encryption);
+               fprintf(fp, "X-Claws-Privacy-System:%s\n", compose->privacy_system);
        }
 
        /* Message-ID of message replying to */
@@ -7968,7 +8114,7 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
        }
 
        /* end of headers */
-       fprintf(fp, "X-Sylpheed-End-Special-Headers: 1\n");
+       fprintf(fp, "X-Claws-End-Special-Headers: 1\n");
 
        if (compose_write_to_file(compose, fp, COMPOSE_WRITE_FOR_STORE, action != COMPOSE_AUTO_SAVE) < 0) {
                fclose(fp);
@@ -8009,12 +8155,15 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                        procmsg_msginfo_set_flags(newmsginfo, 0,
                                                  MSG_HAS_ATTACHMENT);
 
+               if (action == COMPOSE_DRAFT_FOR_EXIT) {
+                       compose_register_draft(newmsginfo);
+               }
                procmsg_msginfo_free(newmsginfo);
        }
        
        folder_item_scan(draft);
        
-       if (action == COMPOSE_QUIT_EDITING) {
+       if (action == COMPOSE_QUIT_EDITING || action == COMPOSE_DRAFT_FOR_EXIT) {
                lock = FALSE;
                g_mutex_unlock(compose->mutex); /* must be done before closing */
                compose_close(compose);
@@ -8996,7 +9145,7 @@ static void compose_toggle_remove_refs_cb(gpointer data, guint action,
                compose->remove_references = FALSE;
 }
 
-gboolean compose_headerentry_key_press_event_cb(GtkWidget *entry,
+static gboolean compose_headerentry_key_press_event_cb(GtkWidget *entry,
                                            GdkEventKey *event,
                                            ComposeHeaderEntry *headerentry)
 {
@@ -9028,7 +9177,7 @@ gboolean compose_headerentry_key_press_event_cb(GtkWidget *entry,
        return FALSE;
 }
 
-gboolean compose_headerentry_changed_cb(GtkWidget *entry,
+static gboolean compose_headerentry_changed_cb(GtkWidget *entry,
                                    ComposeHeaderEntry *headerentry)
 {
        if (strlen(gtk_entry_get_text(GTK_ENTRY(entry))) != 0) {
@@ -9088,7 +9237,7 @@ static void text_inserted(GtkTextBuffer *buffer, GtkTextIter *iter,
                mark = gtk_text_buffer_create_mark(buffer, NULL, iter, FALSE);
                gtk_text_buffer_place_cursor(buffer, iter);
 
-               compose_quote_fmt(compose, NULL, "%Q", qmark, new_text, TRUE,
+               compose_quote_fmt(compose, NULL, "%Q", qmark, new_text, TRUE, FALSE,
                                                  _("Quote format error."));
                quote_fmt_reset_vartable();
                g_free(new_text);
@@ -9122,7 +9271,7 @@ static void text_inserted(GtkTextBuffer *buffer, GtkTextIter *iter,
 
        if (prefs_common.autosave && 
            gtk_text_buffer_get_char_count(buffer) % prefs_common.autosave_length == 0)
-               compose->draft_timeout_tag = gtk_timeout_add
+               compose->draft_timeout_tag = g_timeout_add
                        (500, (GtkFunction) compose_defer_auto_save_draft, compose);
 }
 static gint compose_defer_auto_save_draft(Compose *compose)
@@ -9271,7 +9420,7 @@ static void compose_reply_from_messageview_real(MessageView *msgview, GSList *ms
        if (g_slist_length(msginfo_list) == 1 && !opening_multiple) {
                MimeInfo *mimeinfo = messageview_get_selected_mime_part(msgview);
                MsgInfo *orig_msginfo = (MsgInfo *)msginfo_list->data;
-               
+
                if (mimeinfo != NULL && mimeinfo->type == MIMETYPE_MESSAGE && 
                    !g_ascii_strcasecmp(mimeinfo->subtype, "rfc822")) {
                        tmp_msginfo = procmsg_msginfo_new_from_mimeinfo(
@@ -9431,6 +9580,29 @@ static MsgInfo *compose_msginfo_new_from_compose(Compose *compose)
        return newmsginfo;
 }
 
+#ifdef USE_ASPELL
+/* update compose's dictionaries from folder dict settings */
+static void compose_set_dictionaries_from_folder_prefs(Compose *compose,
+                                               FolderItem *folder_item)
+{
+       g_return_if_fail(compose != NULL);
+
+       if (compose->gtkaspell && folder_item && folder_item->prefs) {
+               FolderItemPrefs *prefs = folder_item->prefs;
+
+               if (prefs->enable_default_dictionary)
+                       gtkaspell_change_dict(compose->gtkaspell,
+                                       prefs->default_dictionary, FALSE);
+               if (folder_item->prefs->enable_default_alt_dictionary)
+                       gtkaspell_change_alt_dict(compose->gtkaspell,
+                                       prefs->default_alt_dictionary);
+               if (prefs->enable_default_dictionary
+                       || prefs->enable_default_alt_dictionary)
+                       compose_spell_menu_changed(compose);
+       }
+}
+#endif
+
 /*
  * End of Source.
  */