Don't ignore value of 'Save copy of outgoing messages to this folder instead of Sent...
[claws.git] / src / compose.c
index ba36887ed7c780d70f2a8d25edcdb1679293d706..32515f6573051c7d7019d014e4f0662730a9bd5a 100644 (file)
 #include "procmsg.h"
 #include "menu.h"
 #include "stock_pixmap.h"
-#include "send.h"
+#include "send_message.h"
 #include "imap.h"
 #include "news.h"
 #include "customheader.h"
 #include "prefs_common.h"
 #include "prefs_account.h"
-#include "prefs_actions.h"
+#include "action.h"
 #include "account.h"
 #include "filesel.h"
 #include "procheader.h"
@@ -196,11 +196,11 @@ static void compose_reply_set_entry               (Compose        *compose,
                                                 followup_and_reply_to);
 static void compose_reedit_set_entry           (Compose        *compose,
                                                 MsgInfo        *msginfo);
-static void compose_insert_sig                 (Compose        *compose);
+static void compose_insert_sig                 (Compose        *compose,
+                                                gboolean        replace);
+static gchar *compose_get_signature_str                (Compose        *compose);
 static void compose_insert_file                        (Compose        *compose,
                                                 const gchar    *file);
-static void compose_insert_command_output      (Compose        *compose,
-                                                const gchar    *cmdline);
 static void compose_attach_append              (Compose        *compose,
                                                 const gchar    *file,
                                                 const gchar    *type,
@@ -213,7 +213,8 @@ static void compose_wrap_line_all_full              (Compose        *compose,
                                                 gboolean        autowrap);
 static void compose_set_title                  (Compose        *compose);
 static void compose_select_account             (Compose        *compose,
-                                                PrefsAccount   *account);
+                                                PrefsAccount   *account,
+                                                gboolean        init);
 
 static PrefsAccount *compose_current_mail_account(void);
 /* static gint compose_send                    (Compose        *compose); */
@@ -246,7 +247,8 @@ static gint compose_write_headers           (Compose        *compose,
 static void compose_convert_header             (gchar          *dest,
                                                 gint            len,
                                                 gchar          *src,
-                                                gint            header_len);
+                                                gint            header_len,
+                                                gboolean        addr_field);
 static void compose_generate_msgid             (Compose        *compose,
                                                 gchar          *buf,
                                                 gint            len);
@@ -325,6 +327,9 @@ static void compose_attach_cb               (gpointer        data,
 static void compose_insert_file_cb     (gpointer        data,
                                         guint           action,
                                         GtkWidget      *widget);
+static void compose_insert_sig_cb      (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
 
 static void compose_close_cb           (gpointer        data,
                                         guint           action,
@@ -410,6 +415,8 @@ static void activate_gnupg_mode     (Compose *compose,
 #endif
 static void compose_toggle_return_receipt_cb(gpointer data, guint action,
                                             GtkWidget *widget);
+static void compose_toggle_remove_refs_cb(gpointer data, guint action,
+                                            GtkWidget *widget);
 static void compose_set_priority_cb    (gpointer        data,
                                         guint           action,
                                         GtkWidget      *widget);
@@ -477,6 +484,7 @@ static void compose_check_forwards_go          (Compose *compose);
 #endif
 
 static gboolean compose_send_control_enter     (Compose        *compose);
+static gint compose_defer_auto_save_draft      (Compose        *compose);
 
 static GtkItemFactoryEntry compose_popup_entries[] =
 {
@@ -491,7 +499,7 @@ static GtkItemFactoryEntry compose_entries[] =
        {N_("/_File"),                          NULL, NULL, 0, "<Branch>"},
        {N_("/_File/_Attach file"),             "<control>M", compose_attach_cb,      0, NULL},
        {N_("/_File/_Insert file"),             "<control>I", compose_insert_file_cb, 0, NULL},
-       {N_("/_File/Insert si_gnature"),        "<control>G", compose_insert_sig,     0, NULL},
+       {N_("/_File/Insert si_gnature"),        "<control>G", compose_insert_sig_cb,  0, NULL},
        {N_("/_File/---"),                      NULL, NULL, 0, "<Separator>"},
        {N_("/_File/_Close"),                   "<control>W", compose_close_cb, 0, NULL},
 
@@ -652,6 +660,7 @@ static GtkItemFactoryEntry compose_entries[] =
        {N_("/_Message/Priority/_Lowest"),  NULL, compose_set_priority_cb, PRIORITY_LOWEST, "/Message/Priority/Highest"},
        {N_("/_Message/---"),           NULL,           NULL,   0, "<Separator>"},
        {N_("/_Message/_Request Return Receipt"),       NULL, compose_toggle_return_receipt_cb, 0, "<ToggleItem>"},
+       {N_("/_Message/Remo_ve references"),    NULL, compose_toggle_remove_refs_cb, 0, "<ToggleItem>"},
        {N_("/_Tools"),                 NULL, NULL, 0, "<Branch>"},
        {N_("/_Tools/Show _ruler"),     NULL, compose_toggle_ruler_cb, 0, "<ToggleItem>"},
        {N_("/_Tools/_Address book"),   "<shift><control>A", compose_address_cb , 0, NULL},
@@ -700,8 +709,15 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI
        text = GTK_STEXT(compose->text);
        gtk_stext_freeze(text);
 
+#ifdef USE_ASPELL
+       if (item && item->prefs && item->prefs->enable_default_dictionary &&
+           compose->gtkaspell) 
+               gtkaspell_change_dict(compose->gtkaspell, 
+                   item->prefs->default_dictionary);
+#endif
+
        if (account->auto_sig)
-               compose_insert_sig(compose);
+               compose_insert_sig(compose, FALSE);
        gtk_editable_set_position(GTK_EDITABLE(text), 0);
        gtk_stext_set_point(text, 0);
 
@@ -787,6 +803,91 @@ Compose *compose_new_followup_and_replyto(PrefsAccount *account,
 }
 */
 
+void compose_reply_mode(ComposeMode mode, GSList *msginfo_list, gchar *body)
+{
+       MsgInfo *msginfo;
+       guint list_len;
+
+       g_return_if_fail(msginfo_list != NULL);
+
+       msginfo = (MsgInfo*)g_slist_nth_data(msginfo_list, 0);
+       g_return_if_fail(msginfo != NULL);
+
+       list_len = g_slist_length(msginfo_list);
+
+       switch (mode) {
+       case COMPOSE_REPLY:
+               compose_reply(msginfo, prefs_common.reply_with_quote,
+                             FALSE, prefs_common.default_reply_list, FALSE, body);
+               break;
+       case COMPOSE_REPLY_WITH_QUOTE:
+               compose_reply(msginfo, TRUE, FALSE, prefs_common.default_reply_list, FALSE, body);
+               break;
+       case COMPOSE_REPLY_WITHOUT_QUOTE:
+               compose_reply(msginfo, FALSE, FALSE, prefs_common.default_reply_list, FALSE, NULL);
+               break;
+       case COMPOSE_REPLY_TO_SENDER:
+               compose_reply(msginfo, prefs_common.reply_with_quote,
+                             FALSE, FALSE, TRUE, body);
+               break;
+       case COMPOSE_FOLLOWUP_AND_REPLY_TO:
+               compose_followup_and_reply_to(msginfo,
+                                             prefs_common.reply_with_quote,
+                                             FALSE, FALSE, body);
+               break;
+       case COMPOSE_REPLY_TO_SENDER_WITH_QUOTE:
+               compose_reply(msginfo, TRUE, FALSE, FALSE, TRUE, body);
+               break;
+       case COMPOSE_REPLY_TO_SENDER_WITHOUT_QUOTE:
+               compose_reply(msginfo, FALSE, FALSE, FALSE, TRUE, NULL);
+               break;
+       case COMPOSE_REPLY_TO_ALL:
+               compose_reply(msginfo, prefs_common.reply_with_quote,
+                             TRUE, FALSE, FALSE, body);
+               break;
+       case COMPOSE_REPLY_TO_ALL_WITH_QUOTE:
+               compose_reply(msginfo, TRUE, TRUE, FALSE, FALSE, body);
+               break;
+       case COMPOSE_REPLY_TO_ALL_WITHOUT_QUOTE:
+               compose_reply(msginfo, FALSE, TRUE, FALSE, FALSE, NULL);
+               break;
+       case COMPOSE_REPLY_TO_LIST:
+               compose_reply(msginfo, prefs_common.reply_with_quote,
+                             FALSE, TRUE, FALSE, body);
+               break;
+       case COMPOSE_REPLY_TO_LIST_WITH_QUOTE:
+               compose_reply(msginfo, TRUE, FALSE, TRUE, FALSE, body);
+               break;
+       case COMPOSE_REPLY_TO_LIST_WITHOUT_QUOTE:
+               compose_reply(msginfo, FALSE, FALSE, TRUE, FALSE, NULL);
+               break;
+       case COMPOSE_FORWARD:
+               if (prefs_common.forward_as_attachment) {
+                       compose_reply_mode(COMPOSE_FORWARD_AS_ATTACH, msginfo_list, body);
+                       return;
+               } else {
+                       compose_reply_mode(COMPOSE_FORWARD_INLINE, msginfo_list, body);
+                       return;
+               }
+               break;
+       case COMPOSE_FORWARD_INLINE:
+               /* check if we reply to more than one Message */
+               if (list_len == 1) {
+                       compose_forward(NULL, msginfo, FALSE, body);
+                       break;
+               } 
+               /* more messages FALL THROUGH */
+       case COMPOSE_FORWARD_AS_ATTACH:
+               compose_forward_multiple(NULL, msginfo_list);
+               break;
+       case COMPOSE_REDIRECT:
+               compose_redirect(NULL, msginfo);
+               break;
+       default:
+               g_warning("compose_reply(): invalid Compose Mode: %d\n", mode);
+       }
+}
+
 void compose_reply(MsgInfo *msginfo, gboolean quote, gboolean to_all,
                   gboolean to_ml, gboolean to_sender, 
                   const gchar *body)
@@ -810,6 +911,7 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
                                  gboolean followup_and_reply_to,
                                  const gchar *body)
 {
+       GtkItemFactory *ifactory;
        Compose *compose;
        PrefsAccount *account = NULL;
        PrefsAccount *reply_account;
@@ -834,17 +936,17 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
                reply_account = account;
 
        compose = compose_create(account, COMPOSE_REPLY);
+       ifactory = gtk_item_factory_from_widget(compose->menubar);
+
+       menu_set_toggle(ifactory, "/Message/Remove references", FALSE);
+       menu_set_sensitive(ifactory, "/Message/Remove references", TRUE);
 
        compose->replyinfo = procmsg_msginfo_get_full_info(msginfo);
        if (!compose->replyinfo)
                compose->replyinfo = procmsg_msginfo_copy(msginfo);
 
-       if (msginfo->folder && msginfo->folder->ret_rcpt) {
-               GtkItemFactory *ifactory;
-       
-               ifactory = gtk_item_factory_from_widget(compose->menubar);
+       if (msginfo->folder && msginfo->folder->ret_rcpt)
                menu_set_toggle(ifactory, "/Message/Request Return Receipt", TRUE);
-       }
 
        /* Set save folder */
        if (msginfo->folder && msginfo->folder->prefs && msginfo->folder->prefs->save_copy_to_folder) {
@@ -864,22 +966,30 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
        text = GTK_STEXT(compose->text);
        gtk_stext_freeze(text);
 
+#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);
+#endif
+
        if (quote) {
                gchar *qmark;
-               gchar *quote_str;
 
                if (prefs_common.quotemark && *prefs_common.quotemark)
                        qmark = prefs_common.quotemark;
                else
                        qmark = "> ";
 
-               quote_str = compose_quote_fmt(compose, compose->replyinfo,
-                                             prefs_common.quotefmt,
-                                             qmark, body);
+               compose_quote_fmt(compose, compose->replyinfo,
+                                 prefs_common.quotefmt,
+                                 qmark, body);
        }
 
        if (account->auto_sig)
-               compose_insert_sig(compose);
+               compose_insert_sig(compose, FALSE);
 
        if (quote && prefs_common.linewrap_quote)
                compose_wrap_line_all(compose);
@@ -945,51 +1055,57 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
                compose->fwdinfo = procmsg_msginfo_copy(msginfo);
 
        if (msginfo->subject && *msginfo->subject) {
-               gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), "Fw: ");
-               gtk_entry_append_text(GTK_ENTRY(compose->subject_entry),
-                                     msginfo->subject);
+               gchar *buf, *buf2, *p;
+
+               buf = p = g_strdup(msginfo->subject);
+               p += subject_get_prefix_length(p);
+               memmove(buf, p, strlen(p) + 1);
+
+               buf2 = g_strdup_printf("Fw: %s", buf);
+               gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf2);
+               
+               g_free(buf);
+               g_free(buf2);
        }
 
        text = GTK_STEXT(compose->text);
        gtk_stext_freeze(text);
 
+       if (as_attach) {
+               gchar *msgfile;
 
-               if (as_attach) {
-                       gchar *msgfile;
-
-                       msgfile = procmsg_get_message_file_path(msginfo);
-                       if (!is_file_exist(msgfile))
-                               g_warning("%s: file not exist\n", msgfile);
-                       else
-                               compose_attach_append(compose, msgfile, msgfile,
-                                                     "message/rfc822");
+               msgfile = procmsg_get_message_file_path(msginfo);
+               if (!is_file_exist(msgfile))
+                       g_warning("%s: file not exist\n", msgfile);
+               else
+                       compose_attach_append(compose, msgfile, msgfile,
+                                             "message/rfc822");
 
-                       g_free(msgfile);
-               } else {
-                       gchar *qmark;
-                       gchar *quote_str;
-                       MsgInfo *full_msginfo;
+               g_free(msgfile);
+       } else {
+               gchar *qmark;
+               MsgInfo *full_msginfo;
 
-                       full_msginfo = procmsg_msginfo_get_full_info(msginfo);
-                       if (!full_msginfo)
-                               full_msginfo = procmsg_msginfo_copy(msginfo);
+               full_msginfo = procmsg_msginfo_get_full_info(msginfo);
+               if (!full_msginfo)
+                       full_msginfo = procmsg_msginfo_copy(msginfo);
 
-                       if (prefs_common.fw_quotemark &&
-                           *prefs_common.fw_quotemark)
-                               qmark = prefs_common.fw_quotemark;
-                       else
-                               qmark = "> ";
+               if (prefs_common.fw_quotemark &&
+                   *prefs_common.fw_quotemark)
+                       qmark = prefs_common.fw_quotemark;
+               else
+                       qmark = "> ";
 
-                       quote_str = compose_quote_fmt(compose, full_msginfo,
-                                                     prefs_common.fw_quotefmt,
-                                                     qmark, body);
-                       compose_attach_parts(compose, msginfo);
+               compose_quote_fmt(compose, full_msginfo,
+                                 prefs_common.fw_quotefmt,
+                                 qmark, body);
+               compose_attach_parts(compose, msginfo);
 
-                       procmsg_msginfo_free(full_msginfo);
-               }
+               procmsg_msginfo_free(full_msginfo);
+       }
 
        if (account->auto_sig)
-               compose_insert_sig(compose);
+               compose_insert_sig(compose, FALSE);
 
        if (prefs_common.linewrap_quote)
                compose_wrap_line_all(compose);
@@ -1068,7 +1184,7 @@ Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
        }
 
        if (account->auto_sig)
-               compose_insert_sig(compose);
+               compose_insert_sig(compose, FALSE);
 
        if (prefs_common.linewrap_quote)
                compose_wrap_line_all(compose);
@@ -1183,11 +1299,13 @@ Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo)
        Compose *compose;
        gchar *filename;
        GtkItemFactory *ifactory;
+       FolderItem *item;
 
        g_return_val_if_fail(msginfo != NULL, NULL);
 
        if (!account)
-               account = cur_account;
+               account = account_get_reply_account(msginfo,
+                                       prefs_common.reply_account_autosel);
        g_return_val_if_fail(account != NULL, NULL);
 
        compose = compose_create(account, COMPOSE_REDIRECT);
@@ -1206,6 +1324,17 @@ Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo)
 
        compose->redirect_filename = filename;
        
+       /* Set save folder */
+       item = msginfo->folder;
+       if (item && item->prefs && item->prefs->save_copy_to_folder) {
+               gchar *folderidentifier;
+
+               gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), prefs_common.savemsg);
+               folderidentifier = folder_item_get_identifier(item);
+               gtk_entry_set_text(GTK_ENTRY(compose->savemsg_entry), folderidentifier);
+               g_free(folderidentifier);
+       }
+
        compose_attach_parts(compose, msginfo);
 
        if (msginfo->subject)
@@ -1350,7 +1479,7 @@ void compose_toolbar_cb(gint action, gpointer data)
                compose_attach_cb(compose, 0, NULL);
                break;
        case A_SIG:
-               compose_insert_sig(compose);
+               compose_insert_sig(compose, FALSE);
                break;
        case A_EXTEDITOR:
                compose_ext_editor_cb(compose, 0, NULL);
@@ -1401,11 +1530,11 @@ static void compose_entries_set(Compose *compose, const gchar *mailto)
 static gint compose_parse_header(Compose *compose, MsgInfo *msginfo)
 {
        static HeaderEntry hentry[] = {{"Reply-To:",    NULL, TRUE},
-                                      {"Cc:",          NULL, FALSE},
+                                      {"Cc:",          NULL, TRUE},
                                       {"References:",  NULL, FALSE},
-                                      {"Bcc:",         NULL, FALSE},
-                                      {"Newsgroups:",  NULL, FALSE},
-                                      {"Followup-To:", NULL, FALSE},
+                                      {"Bcc:",         NULL, TRUE},
+                                      {"Newsgroups:",  NULL, TRUE},
+                                      {"Followup-To:", NULL, TRUE},
                                       {"List-Post:",   NULL, FALSE},
                                       {"X-Priority:",  NULL, FALSE},
                                       {NULL,           NULL, FALSE}};
@@ -1583,7 +1712,8 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
        gchar *buf;
        gchar *p, *lastp;
        gint len;
-
+       const gchar *trimmed_body = body;
+       
        if (!msginfo)
                msginfo = &dummyinfo;
 
@@ -1600,7 +1730,11 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
        }
 
        if (fmt && *fmt != '\0') {
-               quote_fmt_init(msginfo, quote_str, body);
+               while (trimmed_body && strlen(trimmed_body) > 1
+                       && trimmed_body[0]=='\n')
+                       *trimmed_body++;
+
+               quote_fmt_init(msginfo, quote_str, trimmed_body);
                quote_fmt_scan_string(fmt);
                quote_fmt_parse();
 
@@ -1694,15 +1828,13 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
        if (msginfo->subject && *msginfo->subject) {
                gchar *buf, *buf2, *p;
 
-               buf = g_strdup(msginfo->subject);
-               while (!strncasecmp(buf, "Re:", 3)) {
-                       p = buf + 3;
-                       while (isspace(*p)) p++;
-                       memmove(buf, p, strlen(p) + 1);
-               }
+               buf = p = g_strdup(msginfo->subject);
+               p += subject_get_prefix_length(p);
+               memmove(buf, p, strlen(p) + 1);
 
                buf2 = g_strdup_printf("Re: %s", buf);
                gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf2);
+
                g_free(buf2);
                g_free(buf);
        } else
@@ -1721,28 +1853,33 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
        }
 
        if (replyto && from)
-               cc_list = address_list_append(cc_list, from);
-       cc_list = address_list_append(cc_list, msginfo->to);
-       cc_list = address_list_append(cc_list, compose->cc);
+               cc_list = address_list_append_with_comments(cc_list, from);
+       cc_list = address_list_append_with_comments(cc_list, msginfo->to);
+       cc_list = address_list_append_with_comments(cc_list, compose->cc);
 
        to_table = g_hash_table_new(g_str_hash, g_str_equal);
        if (replyto)
-               g_hash_table_insert(to_table, replyto, GINT_TO_POINTER(1));
+               g_hash_table_insert(to_table, g_strdup(replyto), GINT_TO_POINTER(1));
        if (compose->account)
-               g_hash_table_insert(to_table, compose->account->address,
+               g_hash_table_insert(to_table, g_strdup(compose->account->address),
                                    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;
 
-               if (g_hash_table_lookup(to_table, cur->data) != NULL)
+               addr = g_strdup(cur->data);
+               extract_address(addr);
+
+               if (GPOINTER_TO_INT(g_hash_table_lookup(to_table, addr)) == 1)
                        cc_list = g_slist_remove(cc_list, cur->data);
                else
-                       g_hash_table_insert(to_table, cur->data, cur);
+                       g_hash_table_insert(to_table, addr, GINT_TO_POINTER(1));
 
                cur = next;
        }
+       hash_free_strings(to_table);
        g_hash_table_destroy(to_table);
 
        if (cc_list) {
@@ -1752,6 +1889,7 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
                slist_free_strings(cc_list);
                g_slist_free(cc_list);
        }
+
 }
 
 #define SET_ENTRY(entry, str) \
@@ -1789,97 +1927,116 @@ static void compose_reedit_set_entry(Compose *compose, MsgInfo *msginfo)
 #undef SET_ENTRY
 #undef SET_ADDRESS
 
-static void compose_insert_sig(Compose *compose)
+static void compose_insert_sig(Compose *compose, gboolean replace)
 {
-       static gchar *default_sigfile;
-       gchar *sigfile = NULL;
+       GtkSText *text = GTK_STEXT(compose->text);
+       gint cur_pos;
+       gint len;
 
        g_return_if_fail(compose->account != NULL);
 
-       if (compose->account->sig_type == SIG_FILE) {
-               if (compose->account->sig_path)
-                       sigfile = compose->account->sig_path;
-               else {
-                       if (!default_sigfile)
-                               default_sigfile = g_strconcat
-                                       (get_home_dir(), G_DIR_SEPARATOR_S,
-                                        DEFAULT_SIGNATURE, NULL);
-                       sigfile = default_sigfile;
-               }
+       cur_pos = gtk_editable_get_position(GTK_EDITABLE(text));
 
-               if (!is_file_or_fifo_exist(sigfile)) {
-                       g_warning("can't open signature file: %s\n", sigfile);
-                       return;
-               }
+       gtk_stext_freeze(text);
+
+       if (replace) {
+               len = gtk_stext_get_length(text);
+               gtk_stext_set_point(text, len);
        }
 
-       gtk_stext_insert(GTK_STEXT(compose->text), NULL, NULL, NULL, "\n\n", 2);
-       if (compose->account->sig_sep) {
-               gtk_stext_insert(GTK_STEXT(compose->text), NULL, NULL, NULL,
-                                compose->account->sig_sep, -1);
-               gtk_stext_insert(GTK_STEXT(compose->text), NULL, NULL, NULL,
-                               "\n", 1);
+       if (replace && compose->sig_str) {
+               gint pos;
+
+               if (compose->sig_str[0] == '\0')
+                       pos = -1;
+               else
+                       pos = gtkut_stext_find(text, 0, compose->sig_str, TRUE);
+
+               if (pos != -1) {
+                       len = get_mbs_len(compose->sig_str);
+                       if (len >= 0) {
+                               gtk_stext_set_point(text, pos);
+                               gtk_stext_forward_delete(text, len);
+                       }
+               }
        }
 
-       if (compose->account->sig_type == SIG_COMMAND) {
-               if (compose->account->sig_path)
-                       compose_insert_command_output
-                               (compose, compose->account->sig_path);
-       } else
-               compose_insert_file(compose, sigfile);
+       g_free(compose->sig_str);
+       compose->sig_str = compose_get_signature_str(compose);
+       if (!compose->sig_str || (replace && !compose->account->auto_sig))
+               compose->sig_str = g_strdup("");
+
+       gtk_stext_insert(text, NULL, NULL, NULL, compose->sig_str, -1);
+
+       gtk_stext_thaw(text);
+
+       if (cur_pos > gtk_stext_get_length(text))
+               cur_pos = gtk_stext_get_length(text);
+
+       gtk_editable_set_position(GTK_EDITABLE(text), cur_pos);
+       gtk_stext_set_point(text, cur_pos);
 }
 
-static void compose_insert_file(Compose *compose, const gchar *file)
+static gchar *compose_get_signature_str(Compose *compose)
 {
-       GtkSText *text = GTK_STEXT(compose->text);
-       gchar buf[BUFFSIZE];
-       gint len;
-       FILE *fp;
+       gchar *sig_body = NULL;
+       gchar *sig_str = NULL;
 
-       g_return_if_fail(file != NULL);
+       g_return_val_if_fail(compose->account != NULL, NULL);
 
-       if ((fp = fopen(file, "rb")) == NULL) {
-               FILE_OP_ERROR(file, "fopen");
-               return;
+       if (!compose->account->sig_path)
+               return NULL;
+
+       if (compose->account->sig_type == SIG_FILE) {
+               if (!is_file_or_fifo_exist(compose->account->sig_path)) {
+                       g_warning("can't open signature file: %s\n",
+                                 compose->account->sig_path);
+                       return NULL;
+               }
        }
 
-       gtk_stext_freeze(text);
+       if (compose->account->sig_type == SIG_COMMAND)
+               sig_body = get_command_output(compose->account->sig_path);
+       else {
+               gchar *tmp;
 
-       while (fgets(buf, sizeof(buf), fp) != NULL) {
-               /* strip <CR> if DOS/Windows file,
-                  replace <CR> with <LF> if Macintosh file. */
-               strcrchomp(buf);
-               len = strlen(buf);
-               if (len > 0 && buf[len - 1] != '\n') {
-                       while (--len >= 0)
-                               if (buf[len] == '\r') buf[len] = '\n';
-               }
-               gtk_stext_insert(text, NULL, NULL, NULL, buf, -1);
+               tmp = file_read_to_str(compose->account->sig_path);
+               if (!tmp)
+                       return NULL;
+               sig_body = normalize_newlines(tmp);
+               g_free(tmp);
        }
 
-       gtk_stext_thaw(text);
+       if (compose->account->sig_sep)
+               sig_str = g_strconcat("\n\n", compose->account->sig_sep, "\n", sig_body,
+                                     NULL);
+       else
+               sig_str = g_strconcat("\n\n", sig_body, NULL);
 
-       fclose(fp);
+       g_free(sig_body);
+       
+       return sig_str;
 }
 
-static void compose_insert_command_output(Compose *compose,
-                                         const gchar *cmdline)
+static void compose_insert_file(Compose *compose, const gchar *file)
 {
        GtkSText *text = GTK_STEXT(compose->text);
        gchar buf[BUFFSIZE];
        gint len;
        FILE *fp;
 
-       g_return_if_fail(cmdline != NULL);
+       g_return_if_fail(file != NULL);
 
-       if ((fp = popen(cmdline, "r")) == NULL) {
-               FILE_OP_ERROR(cmdline, "popen");
+       if ((fp = fopen(file, "rb")) == NULL) {
+               FILE_OP_ERROR(file, "fopen");
                return;
        }
 
        gtk_stext_freeze(text);
 
        while (fgets(buf, sizeof(buf), fp) != NULL) {
+               /* strip <CR> if DOS/Windows file,
+                  replace <CR> with <LF> if Macintosh file. */
                strcrchomp(buf);
                len = strlen(buf);
                if (len > 0 && buf[len - 1] != '\n') {
@@ -1891,7 +2048,7 @@ static void compose_insert_command_output(Compose *compose,
 
        gtk_stext_thaw(text);
 
-       pclose(fp);
+       fclose(fp);
 }
 
 static void compose_attach_append(Compose *compose, const gchar *file,
@@ -1940,13 +2097,24 @@ static void compose_attach_append(Compose *compose, const gchar *file,
        if (content_type) {
                ainfo->content_type = g_strdup(content_type);
                if (!strcasecmp(content_type, "message/rfc822")) {
+                       MsgInfo *msginfo;
+                       MsgFlags flags = {0, 0};
+                       gchar *name;
+
                        if (procmime_get_encoding_for_file(file) == ENC_7BIT)
                                ainfo->encoding = ENC_7BIT;
                        else
                                ainfo->encoding = ENC_8BIT;
-                       ainfo->name = g_strdup_printf
-                               (_("Message: %s"),
-                                g_basename(filename ? filename : file));
+
+                       msginfo = procheader_parse_file(file, flags, FALSE, FALSE);
+                       if (msginfo && msginfo->subject)
+                               name = msginfo->subject;
+                       else
+                               name = g_basename(filename ? filename : file);
+
+                       ainfo->name = g_strdup_printf(_("Message: %s"), name);
+
+                       procmsg_msginfo_free(msginfo);
                } else {
                        if (!g_strncasecmp(content_type, "text", 4))
                                ainfo->encoding =
@@ -2015,7 +2183,7 @@ static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
                        child = procmime_mimeinfo_next(child);
                        continue;
                }
-               if(child->parent && child->parent->parent
+               if (child->parent && child->parent->parent
                && !strcasecmp(child->parent->parent->content_type, "multipart/signed")
                && child->mime_type == MIME_TEXT) {
                        /* this is the main text part of a signed message */
@@ -2050,6 +2218,10 @@ static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
        }                                                                    \
 }
 
+#define DISP_WIDTH(len) \
+       ((len > 2 && conv_get_current_charset() == C_UTF_8) ? 2 : \
+        (len == 2 && conv_get_current_charset() == C_UTF_8) ? 1 : len)
+
 #define INDENT_CHARS   ">|#"
 #define SPACE_CHARS    " \t"
 
@@ -2177,7 +2349,7 @@ static void compose_wrap_line(Compose *compose)
                        line_len = cur_len + ch_len;
                }
 
-               if (cur_len + ch_len > prefs_common.linewrap_len &&
+               if (cur_len + DISP_WIDTH(ch_len) > prefs_common.linewrap_len &&
                    line_len > 0) {
                        gint tlen = ch_len;
 
@@ -2198,16 +2370,16 @@ static void compose_wrap_line(Compose *compose)
                        p_end++;
                        cur_pos++;
                        line_pos++;
-                       cur_len = cur_len - line_len + ch_len;
+                       cur_len = cur_len - line_len + DISP_WIDTH(ch_len);
                        line_len = 0;
                        continue;
                }
 
                if (ch_len > 1) {
                        line_pos = cur_pos + 1;
-                       line_len = cur_len + ch_len;
+                       line_len = cur_len + DISP_WIDTH(ch_len);
                }
-               cur_len += ch_len;
+               cur_len += DISP_WIDTH(ch_len);
        }
 
 compose_end:
@@ -2255,6 +2427,10 @@ static guint get_indent_length(GtkSText *text, guint start_pos, guint text_len)
        gboolean is_space;
        gboolean is_indent;
 
+       if (prefs_common.quote_chars == NULL) {
+               return 0 ;
+       }
+
        for (i = start_pos; i < text_len; i++) {
                GET_CHAR(i, cbuf, ch_len);
                if (ch_len > 1)
@@ -2481,6 +2657,14 @@ static void compose_wrap_line_all_full(Compose *compose, gboolean autowrap)
                                g_print("after delete l_pos=");
                                dump_text(text, line_pos, tlen, 1);
 #endif
+                               /* move beginning of line if we are on LF */
+                               GET_CHAR(line_pos, cb, clen);
+                               if (clen == 1 && *cb == '\n')
+                                       line_pos++;
+#ifdef WRAP_DEBUG
+                               g_print("new line_pos=%d\n", line_pos);
+#endif
+
                                continue;
                        }
 
@@ -2504,7 +2688,7 @@ static void compose_wrap_line_all_full(Compose *compose, gboolean autowrap)
                }
 
                /* are we over wrapping length set in preferences ? */
-               if (cur_len + ch_len > linewrap_len) {
+               if (cur_len + DISP_WIDTH(ch_len) > linewrap_len) {
                        gint clen;
 
 #ifdef WRAP_DEBUG
@@ -2560,7 +2744,7 @@ static void compose_wrap_line_all_full(Compose *compose, gboolean autowrap)
                        STEXT_FREEZE();
                        gtk_stext_set_point(text, line_pos);
                        gtk_stext_insert(text, NULL, NULL, NULL, "\n", 1);
-                       /* gtk_stext_compact_buffer(text); */
+                       gtk_stext_compact_buffer(text);
                        tlen++;
                        line_pos++;
                        /* for loop will increase it */
@@ -2602,10 +2786,10 @@ static void compose_wrap_line_all_full(Compose *compose, gboolean autowrap)
 
                if (ch_len > 1) {
                        line_pos = cur_pos + 1;
-                       line_len = cur_len + ch_len;
+                       line_len = cur_len + DISP_WIDTH(ch_len);
                }
                /* advance to next character in buffer */
-               cur_len += ch_len;
+               cur_len += DISP_WIDTH(ch_len);
        }
 
        if (frozen)
@@ -2660,7 +2844,8 @@ compose_current_mail_account(void)
        return ac;
 }
 
-static void compose_select_account(Compose *compose, PrefsAccount *account)
+static void compose_select_account(Compose *compose, PrefsAccount *account,
+                                  gboolean init)
 {
        GtkWidget *menuitem;
        GtkItemFactory *ifactory;
@@ -2745,6 +2930,9 @@ static void compose_select_account(Compose *compose, PrefsAccount *account)
                                       
        activate_gnupg_mode(compose, account);          
 #endif /* USE_GPGME */
+
+       if (!init && compose->mode != COMPOSE_REDIRECT)
+               compose_insert_sig(compose, TRUE);
 }
 
 gboolean compose_check_for_valid_recipient(Compose *compose) {
@@ -2839,6 +3027,8 @@ gint compose_send(Compose *compose)
        g_free(msgpath);
 
        folder_item_remove_msg(folder, msgnum);
+       
+       folder_item_scan(folder);
 
        return val;
 }
@@ -2958,8 +3148,9 @@ gint compose_send(Compose *compose)
 }
 #endif
 
-static gboolean compose_use_attach(Compose *compose) {
-    return(gtk_clist_get_row_data(GTK_CLIST(compose->attach_clist), 0) != NULL);
+static gboolean compose_use_attach(Compose *compose) 
+{
+       return gtk_clist_get_row_data(GTK_CLIST(compose->attach_clist), 0) != NULL;
 }
 
 static gint compose_redirect_write_headers_from_headerlist(Compose *compose, 
@@ -2992,7 +3183,7 @@ static gint compose_redirect_write_headers_from_headerlist(Compose *compose,
                        if (str[0] != '\0') {
                                compose_convert_header
                                        (buf, sizeof(buf), str,
-                                       strlen("Resent-To") + 2);
+                                       strlen("Resent-To") + 2, TRUE);
                                if (first_address) {
                                        fprintf(fp, "Resent-To: ");
                                        first_address = FALSE;
@@ -3028,7 +3219,7 @@ static gint compose_redirect_write_headers(Compose *compose, FILE *fp)
        if (compose->account->name && *compose->account->name) {
                compose_convert_header
                        (buf, sizeof(buf), compose->account->name,
-                        strlen("From: "));
+                        strlen("From: "), TRUE);
                fprintf(fp, "Resent-From: %s <%s>\n",
                        buf, compose->account->address);
        } else
@@ -3041,7 +3232,7 @@ static gint compose_redirect_write_headers(Compose *compose, FILE *fp)
                g_strstrip(str);
                if (*str != '\0') {
                        compose_convert_header(buf, sizeof(buf), str,
-                                              strlen("Subject: "));
+                                              strlen("Subject: "), FALSE);
                        fprintf(fp, "Subject: %s\n", buf);
                }
        }
@@ -3111,7 +3302,8 @@ static gint compose_redirect_write_to_file(Compose *compose, const gchar *file)
                                        compose_convert_header
                                                (buf, sizeof(buf),
                                                 compose->account->name,
-                                                strlen("From: "));
+                                                strlen("From: "),
+                                                FALSE);
                                        fprintf(fdest, "%s <%s>",
                                                buf,
                                                compose->account->address);
@@ -3297,6 +3489,7 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
                                return -1;
                        } else {
                                buf = chars;
+                               out_codeset = src_codeset;
                                chars = NULL;
                        }
                }
@@ -3341,6 +3534,10 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
                fprintf(fp, "\n--%s\n", compose->boundary);
                fprintf(fp, "Content-Type: text/plain; charset=%s\n",
                        out_codeset);
+#if USE_GPGME
+               if (compose->use_signing && !compose->gnupg_mode)
+                       fprintf(fp, "Content-Disposition: inline\n");
+#endif
                fprintf(fp, "Content-Transfer-Encoding: %s\n",
                        procmime_get_encoding_str(encoding));
                fputc('\n', fp);
@@ -3515,6 +3712,7 @@ static gint compose_queue_sub(Compose *compose, gint *msgnum, FolderItem **item,
        GSList *cur;
        gchar buf[BUFFSIZE];
        gint num;
+       MsgFlags flag = {0, 0};
         static gboolean lock = FALSE;
        PrefsAccount *mailac = NULL, *newsac = NULL;
        
@@ -3703,7 +3901,7 @@ static gint compose_queue_sub(Compose *compose, gint *msgnum, FolderItem **item,
                return -1;
        }
        folder_item_scan(queue);
-       if ((num = folder_item_add_msg(queue, tmp, TRUE)) < 0) {
+       if ((num = folder_item_add_msg(queue, tmp, NULL, TRUE)) < 0) {
                g_warning("can't queue the message\n");
                unlink(tmp);
                g_free(tmp);
@@ -3737,9 +3935,6 @@ static void compose_write_attach(Compose *compose, FILE *fp)
 
        for (row = 0; (ainfo = gtk_clist_get_row_data(clist, row)) != NULL;
             row++) {
-               gchar buf[BUFFSIZE];
-               gchar inbuf[B64_LINE_SIZE], outbuf[B64_BUFFSIZE];
-
                if ((attach_fp = fopen(ainfo->file, "rb")) == NULL) {
                        g_warning("Can't open file %s\n", ainfo->file);
                        continue;
@@ -3752,7 +3947,7 @@ static void compose_write_attach(Compose *compose, FILE *fp)
                        fprintf(fp, "Content-Disposition: inline\n");
                } else {
                        compose_convert_header(filename, sizeof(filename),
-                                              ainfo->name, 12);
+                                              ainfo->name, 12, FALSE);
                        fprintf(fp, "Content-Type: %s;\n"
                                    " name=\"%s\"\n",
                                ainfo->content_type, filename);
@@ -3802,8 +3997,7 @@ static void compose_write_attach(Compose *compose, FILE *fp)
 
 #define QUOTE_IF_REQUIRED(out, str)                    \
 {                                                      \
-       if (*str != '"' && (strchr(str, ',')            \
-                       || strchr(str, '.'))) {         \
+       if (*str != '"' && strpbrk(str, ",.[]<>")) {    \
                gchar *__tmp;                           \
                gint len;                               \
                                                        \
@@ -3825,7 +4019,8 @@ static void compose_write_attach(Compose *compose, FILE *fp)
                        compose->to_list = address_list_append               \
                                (compose->to_list, str);                     \
                        compose_convert_header                               \
-                               (buf, sizeof(buf), str, strlen(header) + 2); \
+                               (buf, sizeof(buf), str, strlen(header) + 2,  \
+                                TRUE);                                      \
                        fprintf(fp, "%s: %s\n", header, buf);                \
                }                                                            \
        }                                                                    \
@@ -3837,14 +4032,15 @@ static void compose_write_attach(Compose *compose, FILE *fp)
 
 static gint compose_write_headers_from_headerlist(Compose *compose, 
                                                  FILE *fp, 
-                                                 gchar *header)
+                                                 const gchar *header,
+                                                 const gchar *seperator)
 {
-       gchar buf[BUFFSIZE];
        gchar *str, *header_w_colon, *trans_hdr;
-       gboolean first_address;
+       gboolean write_header = FALSE;
        GSList *list;
        ComposeHeaderEntry *headerentry;
        gchar * headerentryname;
+       GString *headerstr;
 
        if (IS_IN_CUSTOM_HEADER(header)) {
                return 0;
@@ -3852,10 +4048,11 @@ static gint compose_write_headers_from_headerlist(Compose *compose,
 
        debug_print("Writing %s-header\n", header);
 
+       headerstr = g_string_sized_new(64);
+
        header_w_colon = g_strconcat(header, ":", NULL);
        trans_hdr = (prefs_common.trans_hdr ? gettext(header_w_colon) : header_w_colon);
 
-       first_address = TRUE;
        for (list = compose->header_list; list; list = list->next) {
                headerentry = ((ComposeHeaderEntry *)list->data);
                headerentryname = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(headerentry->combo)->entry));
@@ -3865,24 +4062,26 @@ static gint compose_write_headers_from_headerlist(Compose *compose,
                        Xstrdup_a(str, str, return -1);
                        g_strstrip(str);
                        if (str[0] != '\0') {
-                               compose_convert_header
-                                       (buf, sizeof(buf), str,
-                                       strlen(header) + 2);
-                               if (first_address) {
-                                       fprintf(fp, "%s: ", header);
-                                       first_address = FALSE;
-                               } else {
-                                       fprintf(fp, ",");
-                               }
-                               fprintf(fp, "%s", buf);
+                               g_string_append(headerstr, str);
+                               if (write_header)
+                                       g_string_append(headerstr, seperator);
+                               write_header = TRUE;
                        }
                }
        }
-       if (!first_address) {
-               fprintf(fp, "\n");
+       if (write_header) {
+               gchar *buf;
+
+               buf = g_new0(gchar, headerstr->len * 2);
+               compose_convert_header
+                       (buf, headerstr->len * 2, headerstr->str,
+                       strlen(header) + 2, TRUE);
+               fprintf(fp, "%s: %s\n", header, buf);
+               g_free(buf);
        }
 
        g_free(header_w_colon);
+       g_string_free(headerstr, TRUE);
 
        return(0);
 }
@@ -3929,7 +4128,7 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                if (compose->account->name && *compose->account->name) {
                        compose_convert_header
                                (buf, sizeof(buf), compose->account->name,
-                                strlen("From: "));
+                                strlen("From: "), TRUE);
                        QUOTE_IF_REQUIRED(name, buf);
                        fprintf(fp, "From: %s <%s>\n",
                                name, compose->account->address);
@@ -3938,7 +4137,7 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
        }
        
        /* To */
-       compose_write_headers_from_headerlist(compose, fp, "To");
+       compose_write_headers_from_headerlist(compose, fp, "To", ", ");
 #if 0 /* NEW COMPOSE GUI */
        if (compose->use_to) {
                str = gtk_entry_get_text(GTK_ENTRY(compose->to_entry));
@@ -3947,7 +4146,7 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
 #endif
 
        /* Newsgroups */
-       compose_write_headers_from_headerlist(compose, fp, "Newsgroups");
+       compose_write_headers_from_headerlist(compose, fp, "Newsgroups", ",");
 #if 0 /* NEW COMPOSE GUI */
        if (compose->use_newsgroups) {
                str = gtk_entry_get_text(GTK_ENTRY(compose->newsgroups_entry));
@@ -3960,14 +4159,15 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                                        newsgroup_list_append
                                                (compose->newsgroup_list, str);
                                compose_convert_header(buf, sizeof(buf), str,
-                                                      strlen("Newsgroups: "));
+                                                      strlen("Newsgroups: "),
+                                                      TRUE);
                                fprintf(fp, "Newsgroups: %s\n", buf);
                        }
                }
        }
 #endif
        /* Cc */
-       compose_write_headers_from_headerlist(compose, fp, "Cc");
+       compose_write_headers_from_headerlist(compose, fp, "Cc", ", ");
 #if 0 /* NEW COMPOSE GUI */
        if (compose->use_cc) {
                str = gtk_entry_get_text(GTK_ENTRY(compose->cc_entry));
@@ -3975,7 +4175,7 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
        }
 #endif
        /* Bcc */
-       compose_write_headers_from_headerlist(compose, fp, "Bcc");
+       compose_write_headers_from_headerlist(compose, fp, "Bcc", ", ");
 #if 0 /* NEW COMPOSE GUI */
        if (compose->use_bcc) {
                str = gtk_entry_get_text(GTK_ENTRY(compose->bcc_entry));
@@ -3990,7 +4190,7 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                g_strstrip(str);
                if (*str != '\0') {
                        compose_convert_header(buf, sizeof(buf), str,
-                                              strlen("Subject: "));
+                                              strlen("Subject: "), FALSE);
                        fprintf(fp, "Subject: %s\n", buf);
                }
        }
@@ -4002,16 +4202,18 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                compose->msgid = g_strdup(buf);
        }
 
-       /* In-Reply-To */
-       if (compose->inreplyto && compose->to_list)
-               fprintf(fp, "In-Reply-To: <%s>\n", compose->inreplyto);
-
-       /* References */
-       if (compose->references)
-               fprintf(fp, "References: %s\n", compose->references);
+       if (compose->remove_references == FALSE) {
+               /* In-Reply-To */
+               if (compose->inreplyto && compose->to_list)
+                       fprintf(fp, "In-Reply-To: <%s>\n", compose->inreplyto);
+       
+               /* References */
+               if (compose->references)
+                       fprintf(fp, "References: %s\n", compose->references);
+       }
 
        /* Followup-To */
-       compose_write_headers_from_headerlist(compose, fp, "Followup-To");
+       compose_write_headers_from_headerlist(compose, fp, "Followup-To", ",");
 #if 0 /* NEW COMPOSE GUI */
        if (compose->use_followupto && !IS_IN_CUSTOM_HEADER("Followup-To")) {
                str = gtk_entry_get_text(GTK_ENTRY(compose->followup_entry));
@@ -4021,14 +4223,15 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                        remove_space(str);
                        if (*str != '\0') {
                                compose_convert_header(buf, sizeof(buf), str,
-                                                      strlen("Followup-To: "));
+                                                      strlen("Followup-To: "),
+                                                      TRUE);
                                fprintf(fp, "Followup-To: %s\n", buf);
                        }
                }
        }
 #endif
        /* Reply-To */
-       compose_write_headers_from_headerlist(compose, fp, "Reply-To");
+       compose_write_headers_from_headerlist(compose, fp, "Reply-To", ", ");
 #if 0 /* NEW COMPOSE GUI */
        if (compose->use_replyto && !IS_IN_CUSTOM_HEADER("Reply-To")) {
                str = gtk_entry_get_text(GTK_ENTRY(compose->reply_entry));
@@ -4037,7 +4240,8 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                        g_strstrip(str);
                        if (*str != '\0') {
                                compose_convert_header(buf, sizeof(buf), str,
-                                                      strlen("Reply-To: "));
+                                                      strlen("Reply-To: "),
+                                                      TRUE);
                                fprintf(fp, "Reply-To: %s\n", buf);
                        }
                }
@@ -4048,7 +4252,7 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
            !IS_IN_CUSTOM_HEADER("Organization")) {
                compose_convert_header(buf, sizeof(buf),
                                       compose->account->organization,
-                                      strlen("Organization: "));
+                                      strlen("Organization: "), FALSE);
                fprintf(fp, "Organization: %s\n", buf);
        }
 
@@ -4092,7 +4296,7 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                                compose_convert_header
                                        (buf, sizeof(buf),
                                         chdr->value ? chdr->value : "",
-                                        strlen(chdr->name) + 2);
+                                        strlen(chdr->name) + 2, FALSE);
                                fprintf(fp, "%s: %s\n", chdr->name, buf);
                        }
                }
@@ -4101,16 +4305,16 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
        /* MIME */
        fprintf(fp, "Mime-Version: 1.0\n");
        if (compose_use_attach(compose)) {
-               get_rfc822_date(buf, sizeof(buf));
-               subst_char(buf, ' ', '_');
-               subst_char(buf, ',', '_');
-               compose->boundary = g_strdup_printf("Multipart_%s_%08x",
-                                                   buf, (guint)compose);
+               compose->boundary = generate_mime_boundary(NULL);
                fprintf(fp,
                        "Content-Type: multipart/mixed;\n"
                        " boundary=\"%s\"\n", compose->boundary);
        } else {
                fprintf(fp, "Content-Type: text/plain; charset=%s\n", charset);
+#if USE_GPGME
+               if (compose->use_signing && !compose->gnupg_mode)
+                       fprintf(fp, "Content-Disposition: inline\n");
+#endif
                fprintf(fp, "Content-Transfer-Encoding: %s\n",
                        procmime_get_encoding_str(encoding));
        }
@@ -4139,7 +4343,10 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                if (compose->return_receipt) {
                        if (compose->account->name
                            && *compose->account->name) {
-                               compose_convert_header(buf, sizeof(buf), compose->account->name, strlen("Disposition-Notification-To: "));
+                               compose_convert_header(buf, sizeof(buf), 
+                                                      compose->account->name, 
+                                                      strlen("Disposition-Notification-To: "),
+                                                      TRUE);
                                fprintf(fp, "Disposition-Notification-To: %s <%s>\n", buf, compose->account->address);
                        } else
                                fprintf(fp, "Disposition-Notification-To: %s\n", compose->account->address);
@@ -4160,6 +4367,11 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                headerentry = ((ComposeHeaderEntry *)list->data);
                
                tmp = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(headerentry->combo)->entry)));
+               if (strchr(tmp, ' ') != NULL || strchr(tmp, '\r') != NULL || strchr(tmp, '\n') != NULL) {
+                       g_free(tmp);
+                       continue;
+               }
+
                if (!strstr(tmp, ":")) {
                        headername_wcolon = g_strconcat(tmp, ":", NULL);
                        headername = g_strdup(tmp);
@@ -4170,6 +4382,8 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                g_free(tmp);
                
                headervalue = gtk_entry_get_text(GTK_ENTRY(headerentry->entry));
+               subst_char(headervalue, '\r', ' ');
+               subst_char(headervalue, '\n', ' ');
                string = std_headers;
                while (*string != NULL) {
                        headername_trans = prefs_common.trans_hdr ? gettext(*string) : *string;
@@ -4181,8 +4395,7 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                        fprintf(fp, "%s %s\n", headername_wcolon, headervalue);
                                
                g_free(headername);
-               g_free(headername_wcolon);
-               
+               g_free(headername_wcolon);              
        }
 
        /* separator between header and body */
@@ -4194,16 +4407,18 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
 #undef IS_IN_CUSTOM_HEADER
 
 static void compose_convert_header(gchar *dest, gint len, gchar *src,
-                                  gint header_len)
+                                  gint header_len, gboolean addr_field)
 {
        g_return_if_fail(src != NULL);
        g_return_if_fail(dest != NULL);
 
        if (len < 1) return;
 
+       subst_char(src, '\n', ' ');
+       subst_char(src, '\r', ' ');
        g_strchomp(src);
 
-       conv_encode_header(dest, len, src, header_len);
+       conv_encode_header(dest, len, src, header_len, addr_field);
 }
 
 static void compose_generate_msgid(Compose *compose, gchar *buf, gint len)
@@ -4832,6 +5047,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        ifactory = gtk_item_factory_from_widget(menubar);
        menu_set_sensitive(ifactory, "/Edit/Undo", FALSE);
        menu_set_sensitive(ifactory, "/Edit/Redo", FALSE);
+       menu_set_sensitive(ifactory, "/Message/Remove references", FALSE);
 
        tmpl_menu = gtk_item_factory_get_item(ifactory, "/Tools/Template");
 #if 0 /* NEW COMPOSE GUI */
@@ -4860,7 +5076,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        }
 #endif
 
-       update_compose_actions_menu(ifactory, "/Tools/Actions", compose);
+       action_update_compose_menu(ifactory, compose);
 
 
        undostruct = undo_init(text);
@@ -4917,51 +5133,58 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        compose->modified = FALSE;
 
        compose->return_receipt = FALSE;
-       compose->paste_as_quotation = FALSE;
 
        compose->to_list        = NULL;
        compose->newsgroup_list = NULL;
 
+       compose->undostruct = undostruct;
+
+       compose->sig_str = NULL;
+
        compose->exteditor_file    = NULL;
        compose->exteditor_pid     = -1;
        compose->exteditor_readdes = -1;
        compose->exteditor_tag     = -1;
 
-       compose->redirect_filename = NULL;
-       compose->undostruct = undostruct;
 #if USE_ASPELL
        menu_set_sensitive(ifactory, "/Spelling", FALSE);
        if (mode != COMPOSE_REDIRECT) {
                if (prefs_common.enable_aspell && prefs_common.dictionary &&
                    strcmp(prefs_common.dictionary, _("None"))) {
-                       gtkaspell = gtkaspell_new((const gchar*)prefs_common.dictionary,
+                       gtkaspell = gtkaspell_new(prefs_common.aspell_path,
+                                                 prefs_common.dictionary,
                                                  conv_get_current_charset_str(),
                                                  prefs_common.misspelled_col,
                                                  prefs_common.check_while_typing,
                                                  prefs_common.use_alternate,
                                                  GTK_STEXT(text));
                        if (!gtkaspell) {
-                               alertpanel_error(_("Spell checker could not be started.\n%s"), gtkaspellcheckers->error_message);
+                               alertpanel_error(_("Spell checker could not "
+                                               "be started.\n%s"),
+                                               gtkaspell_checkers_strerror());
                                gtkaspell_checkers_reset_error();
                        } else {
 
                                GtkWidget *menuitem;
 
-                               if (!gtkaspell_set_sug_mode(gtkaspell, prefs_common.aspell_sugmode)) {
-                                       debug_print("Aspell: could not set suggestion mode %s\n",
-                                       gtkaspellcheckers->error_message);
+                               if (!gtkaspell_set_sug_mode(gtkaspell,
+                                               prefs_common.aspell_sugmode)) {
+                                       debug_print("Aspell: could not set "
+                                                   "suggestion mode %s\n",
+                                                   gtkaspell_checkers_strerror());
                                        gtkaspell_checkers_reset_error();
                                }
 
-                               menuitem = gtk_item_factory_get_item(ifactory, "/Spelling/Spelling Configuration");
+                               menuitem = gtk_item_factory_get_item(ifactory,
+                                       "/Spelling/Spelling Configuration");
                                gtkaspell_populate_submenu(gtkaspell, menuitem);
                                menu_set_sensitive(ifactory, "/Spelling", TRUE);
-                               }
+                       }
                }
        }
 #endif
 
-       compose_select_account(compose, account);
+       compose_select_account(compose, account, TRUE);
 
 #if USE_ASPELL
         compose->gtkaspell      = gtkaspell;
@@ -4983,7 +5206,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
                gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(compose->header_last->combo)->entry), prefs_common.trans_hdr ? _("Newsgroups:") : "Newsgroups:");
 
        addressbook_set_target_compose(compose);
-       update_compose_actions_menu(ifactory, "/Tools/Actions", compose);
+       action_update_compose_menu(ifactory, compose);
        
        if (mode != COMPOSE_REDIRECT)
                compose_set_template_menu(compose);
@@ -5199,7 +5422,7 @@ static void compose_template_apply(Compose *compose, Template *tmpl,
                compose_entry_append(compose, tmpl->bcc, COMPOSE_BCC);
 
        if (replace)
-               gtk_stext_clear(GTK_STEXT(compose->text));
+               gtkut_stext_clear(GTK_STEXT(compose->text));
 
        if ((compose->replyinfo == NULL) && (compose->fwdinfo == NULL)) {
                parsed_str = compose_quote_fmt(compose, NULL, tmpl->value,
@@ -5221,7 +5444,7 @@ static void compose_template_apply(Compose *compose, Template *tmpl,
        }
 
        if (replace && parsed_str && compose->account->auto_sig)
-               compose_insert_sig(compose);
+               compose_insert_sig(compose, FALSE);
 
        if (replace && parsed_str) {
                gtk_editable_set_position(GTK_EDITABLE(compose->text), 0);
@@ -5270,6 +5493,10 @@ static void compose_destroy(Compose *compose)
 
        if (compose->redirect_filename)
                g_free(compose->redirect_filename);
+       if (compose->undostruct)
+               undo_destroy(compose->undostruct);
+
+       g_free(compose->sig_str);
 
        g_free(compose->exteditor_file);
 
@@ -5656,20 +5883,20 @@ static void compose_exec_ext_editor(Compose *compose)
                close(pipe_fds[0]);
 
                if (compose_write_body_to_file(compose, tmp) < 0) {
-                       fd_write(pipe_fds[1], "2\n", 2);
+                       fd_write_all(pipe_fds[1], "2\n", 2);
                        _exit(1);
                }
 
                pid_ed = compose_exec_ext_editor_real(tmp);
                if (pid_ed < 0) {
-                       fd_write(pipe_fds[1], "1\n", 2);
+                       fd_write_all(pipe_fds[1], "1\n", 2);
                        _exit(1);
                }
 
                /* wait until editor is terminated */
                waitpid(pid_ed, NULL, 0);
 
-               fd_write(pipe_fds[1], "0\n", 2);
+               fd_write_all(pipe_fds[1], "0\n", 2);
 
                close(pipe_fds[1]);
                _exit(0);
@@ -5970,7 +6197,7 @@ static void account_activated(GtkMenuItem *menuitem, gpointer data)
        g_return_if_fail(ac != NULL);
 
        if (ac != compose->account)
-               compose_select_account(compose, ac);
+               compose_select_account(compose, ac, FALSE);
 }
 
 static void attach_selected(GtkCList *clist, gint row, gint column,
@@ -6027,7 +6254,9 @@ static void compose_allow_user_actions (Compose *compose, gboolean allow)
        toolbar_comp_set_sensitive(compose, allow);
        menu_set_sensitive(ifactory, "/File", allow);
        menu_set_sensitive(ifactory, "/Edit", allow);
+#if USE_ASPELL
        menu_set_sensitive(ifactory, "/Spelling", allow);
+#endif 
        menu_set_sensitive(ifactory, "/Message", allow);
        menu_set_sensitive(ifactory, "/Tools", allow);
        menu_set_sensitive(ifactory, "/Help", allow);
@@ -6074,6 +6303,7 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
        FolderItem *draft;
        gchar *tmp;
        gint msgnum;
+       MsgFlags flag = {0, 0};
        static gboolean lock = FALSE;
        MsgInfo *newmsginfo;
        
@@ -6093,7 +6323,8 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                return;
        }
 
-       if ((msgnum = folder_item_add_msg(draft, tmp, TRUE)) < 0) {
+       folder_item_scan(draft);
+       if ((msgnum = folder_item_add_msg(draft, tmp, &flag, TRUE)) < 0) {
                unlink(tmp);
                g_free(tmp);
                lock = FALSE;
@@ -6113,6 +6344,8 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                procmsg_msginfo_free(newmsginfo);
        }
        
+       folder_item_scan(draft);
+       
        lock = FALSE;
 
        /* 0: quit editing  1: keep editing  2: keep editing (autosave) */
@@ -6189,6 +6422,14 @@ static void compose_insert_file_cb(gpointer data, guint action,
        }
 }
 
+static void compose_insert_sig_cb(gpointer data, guint action,
+                                 GtkWidget *widget)
+{
+       Compose *compose = (Compose *)data;
+
+       compose_insert_sig(compose, FALSE);
+}
+
 static gint compose_delete_cb(GtkWidget *widget, GdkEventAny *event,
                              gpointer data)
 {
@@ -6312,10 +6553,18 @@ static void compose_paste_as_quote_cb(Compose *compose)
 {
        if (compose->focused_editable &&
            GTK_WIDGET_HAS_FOCUS(compose->focused_editable)) {
-               compose->paste_as_quotation = TRUE;
+               /* let text_insert() (called directly or at a later time
+                * after the gtk_editable_paste_clipboard) know that 
+                * text is to be inserted as a quotation. implemented
+                * by using a simple refcount... */
+               gint paste_as_quotation = GPOINTER_TO_INT(gtk_object_get_data(
+                                               GTK_OBJECT(compose->focused_editable),
+                                               "paste_as_quotation"));
+               gtk_object_set_data(GTK_OBJECT(compose->focused_editable),
+                                   "paste_as_quotation",
+                                   GINT_TO_POINTER(paste_as_quotation + 1));
                gtk_editable_paste_clipboard
                        (GTK_EDITABLE(compose->focused_editable));
-               compose->paste_as_quotation = FALSE;
        }
 }
 
@@ -6699,6 +6948,17 @@ static void compose_toggle_return_receipt_cb(gpointer data, guint action,
                compose->return_receipt = FALSE;
 }
 
+static void compose_toggle_remove_refs_cb(gpointer data, guint action,
+                                            GtkWidget *widget)
+{
+       Compose *compose = (Compose *)data;
+
+       if (GTK_CHECK_MENU_ITEM(widget)->active)
+               compose->remove_references = TRUE;
+       else
+               compose->remove_references = FALSE;
+}
+
 void compose_headerentry_key_press_event_cb(GtkWidget *entry,
                                            GdkEventKey *event,
                                            ComposeHeaderEntry *headerentry)
@@ -6769,11 +7029,13 @@ static void text_inserted(GtkWidget *widget, const gchar *text,
                          gint length, gint *position, Compose *compose)
 {
        GtkEditable *editable = GTK_EDITABLE(widget);
+       gint paste_as_quotation = GPOINTER_TO_INT(gtk_object_get_data
+                               (GTK_OBJECT(widget), "paste_as_quotation"));
 
        gtk_signal_handler_block_by_func(GTK_OBJECT(widget),
                                         GTK_SIGNAL_FUNC(text_inserted),
                                         compose);
-       if (compose->paste_as_quotation) {
+       if (paste_as_quotation) {
                gchar *new_text;
                gchar *qmark;
                gint pos;
@@ -6789,6 +7051,8 @@ static void text_inserted(GtkWidget *widget, const gchar *text,
                gtk_editable_set_position(editable, pos);
                *position = pos;
                g_free(new_text);
+               gtk_object_set_data(GTK_OBJECT(widget), "paste_as_quotation",
+                                   GINT_TO_POINTER(paste_as_quotation - 1));
        } else
                gtk_editable_insert_text(editable, text, length, position);
 
@@ -6800,10 +7064,15 @@ static void text_inserted(GtkWidget *widget, const gchar *text,
                                           compose);
        gtk_signal_emit_stop_by_name(GTK_OBJECT(editable), "insert_text");
 
-       
        if (prefs_common.autosave && 
            gtk_stext_get_length(GTK_STEXT(widget)) % prefs_common.autosave_length == 0)
-               compose_draft_cb((gpointer)compose, 2, NULL);
+               gtk_timeout_add(500, (GtkFunction) compose_defer_auto_save_draft, compose);
+}
+
+static gint compose_defer_auto_save_draft(Compose *compose)
+{
+       compose_draft_cb((gpointer)compose, 2, NULL);
+       return FALSE;
 }
 
 static gboolean compose_send_control_enter(Compose *compose)