Fixed double "subject is empty" question.
[claws.git] / src / compose.c
index 10bb92e5465c871f5633d63512458063b2f5a939..8f2d3f21242a248027df5f50fe84c9fb573a2bb5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2001 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2002 Hiroyuki Yamamoto
  *
  * 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
@@ -53,6 +53,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <unistd.h>
 #include <time.h>
 /* #include <sys/utsname.h> */
 #  include <wctype.h>
 #endif
 
-
-#include "gtkstext.h"
-
 #include "intl.h"
 #include "main.h"
 #include "mainwindow.h"
 #include "compose.h"
+#include "gtkstext.h"
 #include "addressbook.h"
 #include "folderview.h"
 #include "procmsg.h"
 #include "menu.h"
+#include "stock_pixmap.h"
 #include "send.h"
 #include "imap.h"
 #include "news.h"
 #include "template.h"
 #include "undo.h"
 #include "foldersel.h"
+#include "prefs_actions.h"
 
 #if USE_GPGME
 #  include "rfc2015.h"
@@ -117,6 +119,25 @@ typedef enum
 
 #define N_ATTACH_COLS          3
 
+typedef enum
+{
+       COMPOSE_CALL_GTK_STEXT_MOVE_BEGINNING_OF_LINE,
+       COMPOSE_CALL_GTK_STEXT_MOVE_FORWARD_CHARACTER,
+       COMPOSE_CALL_GTK_STEXT_MOVE_BACKWARD_CHARACTER,
+       COMPOSE_CALL_GTK_STEXT_MOVE_FORWARD_WORD,
+       COMPOSE_CALL_GTK_STEXT_MOVE_BACKWARD_WORD,
+       COMPOSE_CALL_GTK_STEXT_MOVE_END_OF_LINE,
+       COMPOSE_CALL_GTK_STEXT_MOVE_NEXT_LINE,
+       COMPOSE_CALL_GTK_STEXT_MOVE_PREVIOUS_LINE,
+       COMPOSE_CALL_GTK_STEXT_DELETE_FORWARD_CHARACTER,
+       COMPOSE_CALL_GTK_STEXT_DELETE_BACKWARD_CHARACTER,
+       COMPOSE_CALL_GTK_STEXT_DELETE_FORWARD_WORD,
+       COMPOSE_CALL_GTK_STEXT_DELETE_BACKWARD_WORD,
+       COMPOSE_CALL_GTK_STEXT_DELETE_LINE,
+       COMPOSE_CALL_GTK_STEXT_DELETE_LINE_N,
+       COMPOSE_CALL_GTK_STEXT_DELETE_TO_LINE_END
+} ComposeCallGtkSTextAction;
+
 #define B64_LINE_SIZE          57
 #define B64_BUFFSIZE           77
 
@@ -126,10 +147,6 @@ static GdkColor quote_color = {0, 0, 0, 0xbfff};
 
 static GList *compose_list = NULL;
 
-static void compose_set_undo                   (UndoMain       *undostruct, 
-                                                 gint            undo_state, 
-                                                gint            redo_state, 
-                                                GtkWidget      *changewidget);
 Compose *compose_generic_new                   (PrefsAccount   *account,
                                                 const gchar    *to,
                                                 FolderItem     *item);
@@ -142,7 +159,8 @@ static GtkWidget *compose_account_option_menu_create
                                                (Compose        *compose);
 static void compose_set_template_menu          (Compose        *compose);
 static void compose_template_apply             (Compose        *compose,
-                                                Template       *tmpl);
+                                                Template       *tmpl,
+                                                gboolean        replace);
 static void compose_destroy                    (Compose        *compose);
 
 static void compose_entries_set                        (Compose        *compose,
@@ -155,7 +173,8 @@ static gchar *compose_parse_references              (const gchar    *ref,
 static gchar *compose_quote_fmt                        (Compose        *compose,
                                                 MsgInfo        *msginfo,
                                                 const gchar    *fmt,
-                                                const gchar    *qmark);
+                                                const gchar    *qmark,
+                                                const gchar    *body);
 
 static void compose_reply_set_entry            (Compose        *compose,
                                                 MsgInfo        *msginfo,
@@ -170,28 +189,33 @@ static void compose_insert_file                   (Compose        *compose,
                                                 const gchar    *file);
 static void compose_attach_append              (Compose        *compose,
                                                 const gchar    *file,
-                                                ContentType     cnttype);
-static void compose_attach_append_with_type(Compose *compose,
-                                           const gchar *file,
-                                           const gchar *type,
-                                           ContentType cnttype);
+                                                const gchar    *type,
+                                                const gchar    *content_type);
+static void compose_attach_parts               (Compose        *compose,
+                                                MsgInfo        *msginfo);
 static void compose_wrap_line                  (Compose        *compose);
 static void compose_wrap_line_all              (Compose        *compose);
 static void compose_set_title                  (Compose        *compose);
 
 static PrefsAccount *compose_current_mail_account(void);
 /* static gint compose_send                    (Compose        *compose); */
+static gboolean compose_check_for_valid_recipient
+                                               (Compose        *compose);
+static gboolean compose_check_entries          (Compose        *compose,
+                                                gboolean       check_subject);
 static gint compose_write_to_file              (Compose        *compose,
                                                 const gchar    *file,
                                                 gboolean        is_draft);
 static gint compose_write_body_to_file         (Compose        *compose,
                                                 const gchar    *file);
-static gint compose_save_to_outbox             (Compose        *compose,
-                                                const gchar    *file);
 static gint compose_remove_reedit_target       (Compose        *compose);
 static gint compose_queue                      (Compose        *compose,
                                                 gint           *msgnum,
                                                 FolderItem     **item);
+static gint compose_queue_sub                  (Compose        *compose,
+                                                gint           *msgnum,
+                                                FolderItem     **item,
+                                                gboolean       check_subject);
 static void compose_write_attach               (Compose        *compose,
                                                 FILE           *fp);
 static gint compose_write_headers              (Compose        *compose,
@@ -233,6 +257,11 @@ static void compose_input_cb                       (gpointer           data,
 static void compose_set_ext_editor_sensitive   (Compose           *compose,
                                                 gboolean           sensitive);
 
+static void compose_undo_state_changed         (UndoMain       *undostruct,
+                                                gint            undo_state,
+                                                gint            redo_state,
+                                                gpointer        data);
+
 static gint calc_cursor_xpos   (GtkSText       *text,
                                 gint            extra,
                                 gint            char_width);
@@ -321,13 +350,16 @@ static gint compose_delete_cb             (GtkWidget      *widget,
 static void compose_destroy_cb         (GtkWidget      *widget,
                                         Compose        *compose);
 
-static void compose_undo_cb            (Compose *compose);
-static void compose_redo_cb            (Compose *compose);
+static void compose_undo_cb            (Compose        *compose);
+static void compose_redo_cb            (Compose        *compose);
 static void compose_cut_cb             (Compose        *compose);
 static void compose_copy_cb            (Compose        *compose);
 static void compose_paste_cb           (Compose        *compose);
 static void compose_allsel_cb          (Compose        *compose);
 
+static void compose_gtk_stext_action_cb        (Compose                   *compose,
+                                        ComposeCallGtkSTextAction  action);
+
 static void compose_grab_focus_cb      (GtkWidget      *widget,
                                         Compose        *compose);
 
@@ -410,13 +442,11 @@ static void followupto_activated  (GtkWidget      *widget,
                                         Compose        *compose);
 #endif
 
-static void compose_attach_parts       (Compose        *compose,
-                                        MsgInfo        *msginfo);
-
 static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
                                  gboolean to_all,
                                  gboolean ignore_replyto,
-                                 gboolean followup_and_reply_to);
+                                 gboolean followup_and_reply_to,
+                                 const gchar *body);
 
 void compose_headerentry_changed_cb       (GtkWidget          *entry,
                                            ComposeHeaderEntry *headerentry);
@@ -424,6 +454,19 @@ void compose_headerentry_key_press_event_cb(GtkWidget             *entry,
                                            GdkEventKey        *event,
                                            ComposeHeaderEntry *headerentry);
 
+static void compose_show_first_last_header (Compose *compose, gboolean show_first);
+
+#if USE_PSPELL
+static void compose_check_all             (Compose *compose);
+static void compose_highlight_all         (Compose *compose);
+static void compose_check_backwards       (Compose *compose);
+static void compose_check_forwards_go     (Compose *compose);
+#endif
+
+static gboolean compose_send_control_enter (Compose *compose);
+static void text_activated                (GtkWidget   *widget,
+                                           Compose     *compose);
+
 static GtkItemFactoryEntry compose_popup_entries[] =
 {
        {N_("/_Add..."),        NULL, compose_attach_cb, 0, NULL},
@@ -439,30 +482,136 @@ static GtkItemFactoryEntry compose_entries[] =
        {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/---"),                      NULL, NULL, 0, "<Separator>"},
-       {N_("/_File/_Close"),                   "<alt>W", compose_close_cb, 0, NULL},
-
-       {N_("/_Edit"),             NULL, NULL, 0, "<Branch>"},
-       {N_("/_Edit/_Undo"),       "<control>Z", compose_undo_cb, 0, NULL},
-       {N_("/_Edit/_Redo"),       "<control>Y", compose_redo_cb, 0, NULL},
-       {N_("/_Edit/---"),         NULL, NULL, 0, "<Separator>"},
-       {N_("/_Edit/Cu_t"),        "<control>X", compose_cut_cb,    0, NULL},
-       {N_("/_Edit/_Copy"),       "<control>C", compose_copy_cb,   0, NULL},
-       {N_("/_Edit/_Paste"),      "<control>V", compose_paste_cb,  0, NULL},
-       {N_("/_Edit/Select _all"), "<control>A", compose_allsel_cb, 0, NULL},
-       {N_("/_Edit/---"),         NULL, NULL, 0, "<Separator>"},
-       {N_("/_Edit/_Wrap current paragraph"), "<alt>L", compose_wrap_line, 0, NULL},
+       {N_("/_File/_Close"),                   "<control>W", compose_close_cb, 0, NULL},
+
+       {N_("/_Edit"),                  NULL, NULL, 0, "<Branch>"},
+       {N_("/_Edit/_Undo"),            "<control>Z", compose_undo_cb, 0, NULL},
+       {N_("/_Edit/_Redo"),            "<control>Y", compose_redo_cb, 0, NULL},
+       {N_("/_Edit/---"),              NULL, NULL, 0, "<Separator>"},
+       {N_("/_Edit/Cu_t"),             "<control>X", compose_cut_cb,    0, NULL},
+       {N_("/_Edit/_Copy"),            "<control>C", compose_copy_cb,   0, NULL},
+       {N_("/_Edit/_Paste"),           "<control>V", compose_paste_cb,  0, NULL},
+       {N_("/_Edit/Select _all"),      "<control>A", compose_allsel_cb, 0, NULL},
+       {N_("/_Edit/A_dvanced"),        NULL, NULL, 0, "<Branch>"},
+       {N_("/_Edit/A_dvanced/Move a character backward"),
+                                       "<control>B",
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_MOVE_BACKWARD_CHARACTER,
+                                       NULL},
+       {N_("/_Edit/A_dvanced/Move a character forward"),
+                                       "<control>F",
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_MOVE_FORWARD_CHARACTER,
+                                       NULL},
+       {N_("/_Edit/A_dvanced/Move a word backward"),
+                                       NULL, /* "<alt>B" */
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_MOVE_BACKWARD_WORD,
+                                       NULL},
+       {N_("/_Edit/A_dvanced/Move a word forward"),
+                                       NULL, /* "<alt>F" */
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_MOVE_FORWARD_WORD,
+                                       NULL},
+       {N_("/_Edit/A_dvanced/Move to beginning of line"),
+                                       NULL, /* "<control>A" */
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_MOVE_BEGINNING_OF_LINE,
+                                       NULL},
+       {N_("/_Edit/A_dvanced/Move to end of line"),
+                                       "<control>E",
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_MOVE_END_OF_LINE,
+                                       NULL},
+       {N_("/_Edit/A_dvanced/Move to previous line"),
+                                       "<control>P",
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_MOVE_PREVIOUS_LINE,
+                                       NULL},
+       {N_("/_Edit/A_dvanced/Move to next line"),
+                                       "<control>N",
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_MOVE_NEXT_LINE,
+                                       NULL},
+       {N_("/_Edit/A_dvanced/Delete a character backward"),
+                                       "<control>H",
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_DELETE_BACKWARD_CHARACTER,
+                                       NULL},
+       {N_("/_Edit/A_dvanced/Delete a character forward"),
+                                       "<control>D",
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_DELETE_FORWARD_CHARACTER,
+                                       NULL},
+       {N_("/_Edit/A_dvanced/Delete a word backward"),
+                                       NULL, /* "<control>W" */
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_DELETE_BACKWARD_WORD,
+                                       NULL},
+       {N_("/_Edit/A_dvanced/Delete a word forward"),
+                                       NULL, /* "<alt>D", */
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_DELETE_FORWARD_WORD,
+                                       NULL},
+       {N_("/_Edit/A_dvanced/Delete line"),
+                                       "<control>U",
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_DELETE_LINE,
+                                       NULL},
+       {N_("/_Edit/A_dvanced/Delete entire line"),
+                                       NULL,
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_DELETE_LINE_N,
+                                       NULL},
+       {N_("/_Edit/A_dvanced/Delete to end of line"),
+                                       "<control>K",
+                                       compose_gtk_stext_action_cb,
+                                       COMPOSE_CALL_GTK_STEXT_DELETE_TO_LINE_END,
+                                       NULL},
+       {N_("/_Edit/---"),              NULL, NULL, 0, "<Separator>"},
+       {N_("/_Edit/_Wrap current paragraph"),
+                                       "<control>L", compose_wrap_line, 0, NULL},
        {N_("/_Edit/Wrap all long _lines"),
-                       "<shift><alt>L", compose_wrap_line_all, 0, NULL},
+                                       "<control><alt>L", compose_wrap_line_all, 0, NULL},
        {N_("/_Edit/Edit with e_xternal editor"),
-                       "<alt>X", compose_ext_editor_cb, 0, NULL},
-
+                                       "<shift><control>X", compose_ext_editor_cb, 0, NULL},
+#if USE_PSPELL
+       {N_("/_Spelling"),              NULL, NULL, 0, "<Branch>"},
+       {N_("/_Spelling/_Check all or check selection"),
+                                       NULL, compose_check_all, 0, NULL},
+       {N_("/_Spelling/_Highlight all misspelled words"),
+                                       NULL, compose_highlight_all, 0, NULL},
+       {N_("/_Spelling/Check _backwards misspelled word"),
+                                       NULL, compose_check_backwards , 0, NULL},
+       {N_("/_Spelling/_Forward to next misspelled word"),
+                                       NULL, compose_check_forwards_go, 0, NULL},
+       {N_("/_Spelling/---"),          NULL, NULL, 0, "<Separator>"},
+       {N_("/_Spelling/_Spelling Configuration"),
+                                       NULL, NULL, 0, "<Branch>"},
+#endif
+#if 0 /* NEW COMPOSE GUI */
+       {N_("/_View"),                  NULL, NULL, 0, "<Branch>"},
+       {N_("/_View/_To"),              NULL, compose_toggle_to_cb     , 0, "<ToggleItem>"},
+       {N_("/_View/_Cc"),              NULL, compose_toggle_cc_cb     , 0, "<ToggleItem>"},
+       {N_("/_View/_Bcc"),             NULL, compose_toggle_bcc_cb    , 0, "<ToggleItem>"},
+       {N_("/_View/_Reply to"),        NULL, compose_toggle_replyto_cb, 0, "<ToggleItem>"},
+       {N_("/_View/---"),              NULL, NULL, 0, "<Separator>"},
+       {N_("/_View/_Followup to"),     NULL, compose_toggle_followupto_cb, 0, "<ToggleItem>"},
+       {N_("/_View/---"),              NULL, NULL, 0, "<Separator>"},
+       {N_("/_View/R_uler"),           NULL, compose_toggle_ruler_cb, 0, "<ToggleItem>"},
+       {N_("/_View/---"),              NULL, NULL, 0, "<Separator>"},
+       {N_("/_View/_Attachment"),      NULL, compose_toggle_attach_cb, 0, "<ToggleItem>"},
+#endif
        {N_("/_Message"),               NULL, NULL, 0, "<Branch>"},
        {N_("/_Message/_Send"),         "<control>Return",
                                        compose_send_cb, 0, NULL},
-       {N_("/_Message/Send _later"),   "<shift><alt>S",
+       {N_("/_Message/Send _later"),   "<shift><control>S",
                                        compose_send_later_cb,  0, NULL},
+       {N_("/_Message/---"),           NULL, NULL, 0, "<Separator>"},
        {N_("/_Message/Save to _draft folder"),
-                                       "<alt>D", compose_draft_cb, 0, NULL},
+                                       "<shift><control>D", compose_draft_cb, 0, NULL},
+       {N_("/_Message/Save and _keep editing"),
+                                       "<control>S", compose_draft_cb, 1, NULL},
 #if 0 /* NEW COMPOSE GUI */
        {N_("/_Message/---"),           NULL, NULL, 0, "<Separator>"},
        {N_("/_Message/_To"),           NULL, compose_toggle_to_cb     , 0, "<ToggleItem>"},
@@ -481,11 +630,12 @@ static GtkItemFactoryEntry compose_entries[] =
 #endif /* USE_GPGME */
        {N_("/_Message/---"),           NULL,           NULL,   0, "<Separator>"},
        {N_("/_Message/_Request Return Receipt"),       NULL, compose_toggle_return_receipt_cb, 0, "<ToggleItem>"},
-       {N_("/_Tool"),                  NULL, NULL, 0, "<Branch>"},
-       {N_("/_Tool/Show _ruler"),      NULL, compose_toggle_ruler_cb, 0, "<ToggleItem>"},
-       {N_("/_Tool/_Address book"),    "<alt>A", compose_address_cb , 0, NULL},
-       {N_("/_Tool/_Template"),        NULL, NULL, 0, "<Branch>"},
-       {N_("/_Help"),                  NULL, NULL, 0, "<LastBranch>"},
+       {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},
+       {N_("/_Tools/_Template"),       NULL, NULL, 0, "<Branch>"},
+       {N_("/_Tools/Actio_ns"),        NULL, NULL, 0, "<Branch>"},
+       {N_("/_Help"),                  NULL, NULL, 0, "<Branch>"},
        {N_("/_Help/_About"),           NULL, about_show, 0, NULL}
 };
 
@@ -518,7 +668,7 @@ Compose *compose_bounce(PrefsAccount *account, MsgInfo *msginfo)
                                   msginfo->subject);
        gtk_editable_set_editable(GTK_EDITABLE(c->subject_entry), FALSE);
 
-       compose_quote_fmt(c, msginfo, "%M", NULL);
+       compose_quote_fmt(c, msginfo, "%M", NULL, NULL);
        gtk_editable_set_editable(GTK_EDITABLE(c->text), FALSE);
 
        ifactory = gtk_item_factory_from_widget(c->popupmenu);
@@ -540,7 +690,7 @@ Compose *compose_bounce(PrefsAccount *account, MsgInfo *msginfo)
        menu_set_sensitive(ifactory, "/Message/Encrypt", FALSE);
 #endif
        menu_set_sensitive(ifactory, "/Message/Request Return Receipt", FALSE);
-       menu_set_sensitive(ifactory, "/Tool/Template", FALSE);
+       menu_set_sensitive(ifactory, "/Tools/Template", FALSE);
        
        gtk_widget_set_sensitive(c->insert_btn, FALSE);
        gtk_widget_set_sensitive(c->attach_btn, FALSE);
@@ -597,7 +747,19 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI
                        compose_entry_append(compose, mailto, COMPOSE_NEWSGROUPS);
                }
        }
-       gtk_widget_grab_focus(compose->subject_entry);
+       compose_show_first_last_header(compose, TRUE);
+
+       /* Set save 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);
+       }
+
+       gtk_widget_grab_focus(compose->header_last->entry);
 
        if (prefs_common.auto_exteditor)
                compose_exec_ext_editor(compose);
@@ -639,22 +801,26 @@ Compose *compose_new_followup_and_replyto(PrefsAccount *account,
 */
 
 void compose_reply(MsgInfo *msginfo, gboolean quote, gboolean to_all,
-                  gboolean ignore_replyto)
+                  gboolean ignore_replyto, const gchar *body)
 {
-       compose_generic_reply(msginfo, quote, to_all, ignore_replyto, FALSE);
+       compose_generic_reply(msginfo, quote, to_all, ignore_replyto, FALSE,
+                             body);
 }
 
 void compose_followup_and_reply_to(MsgInfo *msginfo, gboolean quote,
                                   gboolean to_all,
-                                  gboolean ignore_replyto)
+                                  gboolean ignore_replyto,
+                                  const gchar *body)
 {
-       compose_generic_reply(msginfo, quote, to_all, ignore_replyto, TRUE);
+       compose_generic_reply(msginfo, quote, to_all, ignore_replyto, TRUE,
+                             body);
 }
 
 static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
                                  gboolean to_all,
                                  gboolean ignore_replyto,
-                                 gboolean followup_and_reply_to)
+                                 gboolean followup_and_reply_to,
+                                 const gchar *body)
 {
        Compose *compose;
        PrefsAccount *account;
@@ -671,6 +837,9 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
        
        /* select the account for the whole folder (IMAP / NNTP) */
        if (!account)
+               /* FIXME: this is not right, because folder may be nested. we should
+                * ascend the tree until we find a parent with proper account 
+                * information */
                account = msginfo->folder->folder->account;
 
        /* select account by to: and cc: header if enabled */
@@ -729,9 +898,20 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
                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) {
+               gchar *folderidentifier;
+
+               gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), TRUE);
+               folderidentifier = folder_item_get_identifier(msginfo->folder);
+               gtk_entry_set_text(GTK_ENTRY(compose->savemsg_entry), folderidentifier);
+               g_free(folderidentifier);
+       }
+
        if (compose_parse_header(compose, msginfo) < 0) return;
        compose_reply_set_entry(compose, msginfo, to_all, ignore_replyto,
                                followup_and_reply_to);
+       compose_show_first_last_header(compose, TRUE);
 
        text = GTK_STEXT(compose->text);
        gtk_stext_freeze(text);
@@ -747,7 +927,7 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
 
                quote_str = compose_quote_fmt(compose, msginfo,
                                              prefs_common.quotefmt,
-                                             qmark);
+                                             qmark, body);
        }
 
        if (prefs_common.auto_sig)
@@ -762,10 +942,11 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
        gtk_stext_thaw(text);
        gtk_widget_grab_focus(compose->text);
 
-        if (prefs_common.auto_exteditor)
+       if (prefs_common.auto_exteditor)
                compose_exec_ext_editor(compose);
 }
 
+static void set_toolbar_style(Compose *compose);
 
 static gchar *procmime_get_file_name(MimeInfo *mimeinfo)
 {
@@ -817,167 +998,6 @@ static gchar *mime_extract_file(gchar *source, MimeInfo *partinfo)
        return filename;
 }
 
-static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
-{
-       FILE *fp;
-       gchar *file;
-       MimeInfo *mimeinfo;
-       MsgInfo *tmpmsginfo;
-       gchar *p;
-       gchar *boundary;
-       gint boundary_len = 0;
-       gchar buf[BUFFSIZE];
-       glong fpos, prev_fpos;
-       gint npart;
-       gchar *source;
-       gchar *filename;
-
-       g_return_if_fail(msginfo != NULL);
-       
-#if USE_GPGME
-       for (;;) {
-               if ((fp = procmsg_open_message(msginfo)) == NULL) return;
-               mimeinfo = procmime_scan_mime_header(fp);
-               if (!mimeinfo) break;
-
-               if (!MSG_IS_ENCRYPTED(msginfo->flags) &&
-                   rfc2015_is_encrypted(mimeinfo)) {
-                       MSG_SET_TMP_FLAGS(msginfo->flags, MSG_ENCRYPTED);
-               }
-               if (MSG_IS_ENCRYPTED(msginfo->flags) &&
-                   !msginfo->plaintext_file  &&
-                   !msginfo->decryption_failed) {
-                       rfc2015_decrypt_message(msginfo, mimeinfo, fp);
-                       if (msginfo->plaintext_file &&
-                           !msginfo->decryption_failed) {
-                               fclose(fp);
-                               continue;
-                       }
-               }
-               
-               break;
-       }
-#else /* !USE_GPGME */
-       if ((fp = procmsg_open_message(msginfo)) == NULL) return;
-       mimeinfo = procmime_scan_mime_header(fp);
-#endif /* USE_GPGME */
-
-       fclose(fp);
-       if (!mimeinfo) return;
-       if (mimeinfo->mime_type == MIME_TEXT)
-               return;
-
-       if ((fp = procmsg_open_message(msginfo)) == NULL) return;
-
-       g_return_if_fail(mimeinfo != NULL);
-       g_return_if_fail(mimeinfo->mime_type != MIME_TEXT);
-
-       if (mimeinfo->mime_type == MIME_MULTIPART) {
-               g_return_if_fail(mimeinfo->boundary != NULL);
-               g_return_if_fail(mimeinfo->sub == NULL);
-       }
-       g_return_if_fail(fp != NULL);
-
-       boundary = mimeinfo->boundary;
-
-       if (boundary) {
-               boundary_len = strlen(boundary);
-
-               /* look for first boundary */
-               while ((p = fgets(buf, sizeof(buf), fp)) != NULL)
-                       if (IS_BOUNDARY(buf, boundary, boundary_len)) break;
-               if (!p) {
-                       fclose(fp);
-                       return;
-               }
-       }
-
-       if ((fpos = ftell(fp)) < 0) {
-               perror("ftell");
-               fclose(fp);
-               return;
-       }
-
-       for (npart = 0;; npart++) {
-               MimeInfo *partinfo;
-               gboolean eom = FALSE;
-
-               prev_fpos = fpos;
-
-               partinfo = procmime_scan_mime_header(fp);
-               if (!partinfo) break;
-
-               if (npart != 0)
-                       procmime_mimeinfo_insert(mimeinfo, partinfo);
-               else
-                       procmime_mimeinfo_free(partinfo);
-
-               /* look for next boundary */
-               buf[0] = '\0';
-               while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
-                       if (IS_BOUNDARY(buf, boundary, boundary_len)) {
-                               if (buf[2 + boundary_len]     == '-' &&
-                                   buf[2 + boundary_len + 1] == '-')
-                                       eom = TRUE;
-                               break;
-                       }
-               }
-               if (p == NULL)
-                       eom = TRUE;     /* broken MIME message */
-               fpos = ftell(fp);
-
-               partinfo->size = fpos - prev_fpos - strlen(buf);
-
-               if (eom) break;
-       }
-
-       source = procmsg_get_message_file_path(msginfo);
-
-       g_return_if_fail(mimeinfo != NULL);
-
-       if (!mimeinfo->main && mimeinfo->parent)
-               {
-                       filename = mime_extract_file(source, mimeinfo);
-
-                       compose_attach_append_with_type(compose, filename,
-                                                       mimeinfo->content_type,
-                                                       mimeinfo->mime_type);
-
-                       g_free(filename);
-               }
-
-       if (mimeinfo->sub && mimeinfo->sub->children)
-               {
-                       filename = mime_extract_file(source, mimeinfo->sub);
-
-                       compose_attach_append_with_type(compose, filename,
-                                                       mimeinfo->content_type,
-                                                       mimeinfo->sub->mime_type);
-
-                       g_free(filename);
-               }
-
-       if (mimeinfo->children) {
-               MimeInfo *child;
-
-               child = mimeinfo->children;
-               while (child) {
-                       filename = mime_extract_file(source, child);
-
-                       compose_attach_append_with_type(compose, filename,
-                                                       child->content_type,
-                                                       child->mime_type);
-
-                       g_free(filename);
-
-                       child = child->next;
-               }
-       }
-
-       fclose(fp);
-
-       procmime_mimeinfo_free_all(mimeinfo);
-}
 
 
 #define INSERT_FW_HEADER(var, hdr) \
@@ -988,7 +1008,7 @@ if (msginfo->var && *msginfo->var) { \
 }
 
 Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
-                        gboolean as_attach)
+                        gboolean as_attach, const gchar *body)
 {
        Compose *compose;
        /*      PrefsAccount *account; */
@@ -1039,30 +1059,33 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
        text = GTK_STEXT(compose->text);
        gtk_stext_freeze(text);
 
-       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,
-                                             MIME_MESSAGE_RFC822);
+               if (as_attach) {
+                       gchar *msgfile;
 
-               g_free(msgfile);
-       } else {
-               gchar *qmark;
-               gchar *quote_str;
+                       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");
 
-               if (prefs_common.fw_quotemark && *prefs_common.fw_quotemark)
-                       qmark = prefs_common.fw_quotemark;
-               else
-                       qmark = "> ";
+                       g_free(msgfile);
+               } else {
+                       gchar *qmark;
+                       gchar *quote_str;
 
-               quote_str = compose_quote_fmt(compose, msginfo,
-                                             prefs_common.fw_quotefmt, qmark);
-               compose_attach_parts(compose, msginfo);
-       }
+                       if (prefs_common.fw_quotemark &&
+                           *prefs_common.fw_quotemark)
+                               qmark = prefs_common.fw_quotemark;
+                       else
+                               qmark = "> ";
+
+                       quote_str = compose_quote_fmt(compose, msginfo,
+                                                     prefs_common.fw_quotefmt,
+                                                     qmark, body);
+                       compose_attach_parts(compose, msginfo);
+               }
 
        if (prefs_common.auto_sig)
                compose_insert_sig(compose);
@@ -1129,8 +1152,8 @@ Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
                if (!is_file_exist(msgfile))
                        g_warning(_("%s: file not exist\n"), msgfile);
                else
-                       compose_attach_append(compose, msgfile,
-                               MIME_MESSAGE_RFC822);
+                       compose_attach_append(compose, msgfile, msgfile,
+                               "message/rfc822");
                g_free(msgfile);
        }
 
@@ -1157,7 +1180,7 @@ Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
 void compose_reedit(MsgInfo *msginfo)
 {
        Compose *compose;
-       PrefsAccount *account;
+       PrefsAccount *account = NULL;
        GtkSText *text;
        FILE *fp;
        gchar buf[BUFFSIZE];
@@ -1166,9 +1189,23 @@ void compose_reedit(MsgInfo *msginfo)
        g_return_if_fail(msginfo->folder != NULL);
 
         if (msginfo->folder->stype == F_QUEUE) {
-               gchar account_address[BUFFSIZE];
-               if (!get_header_from_msginfo(msginfo, account_address, sizeof(account_address), "S:")) {
-                       account = account_find_from_address(account_address);
+               gchar queueheader_buf[BUFFSIZE];
+               gint id;
+
+               /* Select Account from queue headers */
+               if (!get_header_from_msginfo(msginfo, queueheader_buf, 
+                                            sizeof(queueheader_buf), "NAID:")) {
+                       id = atoi(&queueheader_buf[5]);
+                       account = account_find_from_id(id);
+               }
+               if (!account && !get_header_from_msginfo(msginfo, queueheader_buf, 
+                                                   sizeof(queueheader_buf), "MAID:")) {
+                       id = atoi(&queueheader_buf[5]);
+                       account = account_find_from_id(id);
+               }
+               if (!account && !get_header_from_msginfo(msginfo, queueheader_buf, 
+                                                               sizeof(queueheader_buf), "S:")) {
+                       account = account_find_from_address(queueheader_buf);
                }
        } else 
                account = msginfo->folder->folder->account;
@@ -1186,6 +1223,19 @@ void compose_reedit(MsgInfo *msginfo)
        compose = compose_create(account, COMPOSE_REEDIT);
        compose->targetinfo = procmsg_msginfo_copy(msginfo);
 
+        if (msginfo->folder->stype == F_QUEUE) {
+               gchar queueheader_buf[BUFFSIZE];
+
+               /* Set message save folder */
+               if (!get_header_from_msginfo(msginfo, queueheader_buf, sizeof(queueheader_buf), "SCF:")) {
+                       gint startpos = 0;
+
+                       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), TRUE);
+                       gtk_editable_delete_text(GTK_EDITABLE(compose->savemsg_entry), 0, -1);
+                       gtk_editable_insert_text(GTK_EDITABLE(compose->savemsg_entry), &queueheader_buf[4], strlen(&queueheader_buf[4]), &startpos);
+               }
+       }
+       
        if (compose_parse_header(compose, msginfo) < 0) return;
        compose_reedit_set_entry(compose, msginfo);
 
@@ -1503,7 +1553,8 @@ 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 *fmt, const gchar *qmark,
+                               const gchar *body)
 {
        GtkSText *text = GTK_STEXT(compose->text);
        gchar *quote_str = NULL;
@@ -1512,7 +1563,7 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
        gint len;
 
        if (qmark != NULL) {
-               quote_fmt_init(msginfo, NULL);
+               quote_fmt_init(msginfo, NULL, NULL);
                quote_fmt_scan_string(qmark);
                quote_fmt_parse();
 
@@ -1524,7 +1575,7 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
        }
 
        if (fmt && *fmt != '\0') {
-               quote_fmt_init(msginfo, quote_str);
+               quote_fmt_init(msginfo, quote_str, body);
                quote_fmt_scan_string(fmt);
                quote_fmt_parse();
 
@@ -1537,8 +1588,6 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
                buf = "";
 
        gtk_stext_freeze(text);
-       gtk_stext_set_point(text, 0);
-       gtk_stext_forward_delete(text, gtk_stext_get_length(text));
 
        for (p = buf; *p != '\0'; ) {
                lastp = strchr(p, '\n');
@@ -1559,9 +1608,10 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
                                    gboolean to_all, gboolean ignore_replyto,
                                    gboolean followup_and_reply_to)
 {
-       GSList *cc_list;
+       GSList *cc_list = NULL;
        GSList *cur;
-       gchar *from;
+       gchar *from = NULL;
+       gchar *replyto = NULL;
        GHashTable *to_table;
 
        g_return_if_fail(compose->account != NULL);
@@ -1575,6 +1625,7 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
                                     ? compose->mailinglist
                                     : msginfo->from ? msginfo->from : ""),
                                     COMPOSE_TO);
+
        if (compose->account->protocol == A_NNTP) {
                if (ignore_replyto)
                        compose_entry_append
@@ -1608,15 +1659,30 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
 
        if (!to_all || compose->account->protocol == A_NNTP) return;
 
-       from = g_strdup(compose->replyto ? compose->replyto :
-                       msginfo->from ? msginfo->from : "");
-       extract_address(from);
+       if (compose->replyto) {
+               Xstrdup_a(replyto, compose->replyto, return);
+               extract_address(replyto);
+       }
+       if (msginfo->from) {
+               Xstrdup_a(from, msginfo->from, return);
+               extract_address(from);
+       }
+
+       if (compose->mailinglist && from) {
+               cc_list = address_list_append(cc_list, from);
+       }
+
+       if (replyto && from)
+               cc_list = address_list_append(cc_list, from);
+
+       if (!compose->mailinglist)
+               cc_list = address_list_append(cc_list, msginfo->to);
 
-       cc_list = address_list_append(NULL, msginfo->to);
        cc_list = address_list_append(cc_list, compose->cc);
 
        to_table = g_hash_table_new(g_str_hash, g_str_equal);
-       g_hash_table_insert(to_table, from, GINT_TO_POINTER(1));
+       if (replyto)
+               g_hash_table_insert(to_table, replyto, GINT_TO_POINTER(1));
        if (compose->account)
                g_hash_table_insert(to_table, compose->account->address,
                                    GINT_TO_POINTER(1));
@@ -1633,7 +1699,6 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
                cur = next;
        }
        g_hash_table_destroy(to_table);
-       g_free(from);
 
        if (cc_list) {
                for (cur = cc_list; cur != NULL; cur = cur->next)
@@ -1666,13 +1731,15 @@ static void compose_reedit_set_entry(Compose *compose, MsgInfo *msginfo)
        SET_ADDRESS(COMPOSE_BCC, compose->bcc);
        SET_ADDRESS(COMPOSE_REPLYTO, compose->replyto);
 
+       compose_show_first_last_header(compose, TRUE);
+
 #if 0 /* NEW COMPOSE GUI */
        if (compose->bcc) {
                GtkItemFactory *ifactory;
                GtkWidget *menuitem;
 
                ifactory = gtk_item_factory_from_widget(compose->menubar);
-               menuitem = gtk_item_factory_get_item(ifactory, "/Message/Bcc");
+               menuitem = gtk_item_factory_get_item(ifactory, "/View/Bcc");
                gtk_check_menu_item_set_active
                        (GTK_CHECK_MENU_ITEM(menuitem), TRUE);
        }
@@ -1682,7 +1749,7 @@ static void compose_reedit_set_entry(Compose *compose, MsgInfo *msginfo)
 
                ifactory = gtk_item_factory_from_widget(compose->menubar);
                menuitem = gtk_item_factory_get_item
-                       (ifactory, "/Message/Reply to");
+                       (ifactory, "/View/Reply to");
                gtk_check_menu_item_set_active
                        (GTK_CHECK_MENU_ITEM(menuitem), TRUE);
        }
@@ -1741,12 +1808,11 @@ static void compose_insert_sig(Compose *compose)
 
        if (compose->account && compose->account->sig_path)
                sigfile = g_strdup(compose->account->sig_path);
-       else {
+       else
                sigfile = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
                                      DEFAULT_SIGNATURE, NULL);
-       }
 
-       if (!is_file_or_fifo_exist(sigfile) & (sigfile[0] != '|')) {
+       if (!is_file_or_fifo_exist(sigfile) && sigfile[0] != '|') {
                g_free(sigfile);
                return;
        }
@@ -1760,13 +1826,9 @@ static void compose_insert_sig(Compose *compose)
        }
 
        if (sigfile[0] == '|')
-       {
                compose_exec_sig(compose, sigfile);
-       }
        else
-       {
                compose_insert_file(compose, sigfile);
-       }
        g_free(sigfile);
 }
 
@@ -1779,7 +1841,7 @@ static void compose_insert_file(Compose *compose, const gchar *file)
 
        g_return_if_fail(file != NULL);
 
-       if ((fp = fopen(file, "r")) == NULL) {
+       if ((fp = fopen(file, "rb")) == NULL) {
                FILE_OP_ERROR(file, "fopen");
                return;
        }
@@ -1787,18 +1849,15 @@ static void compose_insert_file(Compose *compose, const gchar *file)
        gtk_stext_freeze(text);
 
        while (fgets(buf, sizeof(buf), fp) != NULL) {
-               /* Strip <CR> if DOS/Windoze file, replace <CR> with <LF> if MAC file */
+               /* strip <CR> if DOS/Windows file,
+                  replace <CR> with <LF> if Macintosh file. */
+               strcrchomp(buf);
                len = strlen(buf);
-               if (len > 1 && buf[len - 2] == '\r' && buf[len - 1] == '\n') {
-                       buf[len - 2] = '\n';
-                       buf[len - 1] = '\0';
-               } else {
-                       while (--len > 0)
-                               if (buf[len] == '\r')
-                                       buf[len] = '\n';
+               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);
+               gtk_stext_insert(text, NULL, NULL, NULL, buf, -1);
        }
 
        gtk_stext_thaw(text);
@@ -1806,30 +1865,15 @@ static void compose_insert_file(Compose *compose, const gchar *file)
        fclose(fp);
 }
 
-static void compose_attach_info(Compose * compose, AttachInfo * ainfo,
-                               ContentType cnttype)
-{
-       gchar *text[N_ATTACH_COLS];
-       gint row;
-
-       text[COL_MIMETYPE] = ainfo->content_type;
-       text[COL_SIZE] = to_human_readable(ainfo->size);
-       text[COL_NAME] = ainfo->name;
-
-       row = gtk_clist_append(GTK_CLIST(compose->attach_clist), text);
-       gtk_clist_set_row_data(GTK_CLIST(compose->attach_clist), row, ainfo);
-
-       if (cnttype != MIME_MESSAGE_RFC822)
-               compose_changed_cb(NULL, compose);
-}
-
-static void compose_attach_append_with_type(Compose *compose,
-                                           const gchar *file,
-                                           const gchar *type,
-                                           ContentType cnttype)
+static void compose_attach_append(Compose *compose, const gchar *file,
+                                 const gchar *filename,
+                                 const gchar *content_type)
 {
        AttachInfo *ainfo;
+       gchar *text[N_ATTACH_COLS];
+       FILE *fp;
        off_t size;
+       gint row;
 
        if (!is_file_exist(file)) {
                g_warning(_("File %s doesn't exist\n"), file);
@@ -1840,9 +1884,15 @@ static void compose_attach_append_with_type(Compose *compose,
                return;
        }
        if (size == 0) {
-               alertpanel_notice(_("File %s is empty\n"), file);
+               alertpanel_notice(_("File %s is empty."), file);
+               return;
+       }
+       if ((fp = fopen(file, "rb")) == NULL) {
+               alertpanel_error(_("Can't read %s."), file);
                return;
        }
+       fclose(fp);
+
 #if 0 /* NEW COMPOSE GUI */
        if (!compose->use_attach) {
                GtkItemFactory *ifactory;
@@ -1850,7 +1900,7 @@ static void compose_attach_append_with_type(Compose *compose,
 
                ifactory = gtk_item_factory_from_widget(compose->menubar);
                menuitem = gtk_item_factory_get_item(ifactory,
-                                                    "/Message/Attach");
+                                                    "/View/Attachment");
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),
                                               TRUE);
        }
@@ -1858,84 +1908,104 @@ static void compose_attach_append_with_type(Compose *compose,
        ainfo = g_new0(AttachInfo, 1);
        ainfo->file = g_strdup(file);
 
-       if (cnttype == MIME_MESSAGE_RFC822) {
-               ainfo->encoding = ENC_7BIT;
-               ainfo->name = g_strdup_printf(_("Message: %s"),
-                                             g_basename(file));
+       if (content_type) {
+               ainfo->content_type = g_strdup(content_type);
+               if (!strcasecmp(content_type, "message/rfc822")) {
+                       ainfo->encoding = ENC_7BIT;
+                       ainfo->name = g_strdup_printf
+                               (_("Message: %s"),
+                                g_basename(filename ? filename : file));
+               } else {
+                       ainfo->encoding = ENC_BASE64;
+                       ainfo->name = g_strdup
+                               (g_basename(filename ? filename : file));
+               }
        } else {
+               ainfo->content_type = procmime_get_mime_type(file);
+               if (!ainfo->content_type)
+                       ainfo->content_type =
+                               g_strdup("application/octet-stream");
                ainfo->encoding = ENC_BASE64;
-               ainfo->name = g_strdup(g_basename(file));
+               ainfo->name = g_strdup(g_basename(filename ? filename : file)); 
        }
-
-       ainfo->content_type = g_strdup(type);
        ainfo->size = size;
 
-       compose_attach_info(compose, ainfo, cnttype);
+       text[COL_MIMETYPE] = ainfo->content_type;
+       text[COL_SIZE] = to_human_readable(size);
+       text[COL_NAME] = ainfo->name;
+
+       row = gtk_clist_append(GTK_CLIST(compose->attach_clist), text);
+       gtk_clist_set_row_data(GTK_CLIST(compose->attach_clist), row, ainfo);
 }
 
-static void compose_attach_append(Compose *compose, const gchar *file,
-                                 ContentType cnttype)
+#define IS_FIRST_PART_TEXT(info) \
+       ((info->mime_type == MIME_TEXT || info->mime_type == MIME_TEXT_HTML || \
+         info->mime_type == MIME_TEXT_ENRICHED) || \
+        (info->mime_type == MIME_MULTIPART && info->content_type && \
+         !strcasecmp(info->content_type, "multipart/alternative") && \
+         (info->children && \
+          (info->children->mime_type == MIME_TEXT || \
+           info->children->mime_type == MIME_TEXT_HTML || \
+           info->children->mime_type == MIME_TEXT_ENRICHED))))
+
+static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
 {
-       AttachInfo *ainfo;
-       gchar *text[N_ATTACH_COLS];
-       off_t size;
-       gint row;
+       MimeInfo *mimeinfo;
+       MimeInfo *child;
+       gchar *infile;
+       gchar *outfile;
 
-       if (!is_file_exist(file)) {
-               g_warning(_("File %s doesn't exist\n"), file);
-               return;
-       }
-       if ((size = get_file_size(file)) < 0) {
-               g_warning(_("Can't get file size of %s\n"), file);
-               return;
-       }
-       if (size == 0) {
-               alertpanel_notice(_("File %s is empty\n"), file);
+       mimeinfo = procmime_scan_message(msginfo);
+       if (!mimeinfo) return;
+
+       /* skip first text (presumably message body) */
+       child = mimeinfo->children;
+       if (!child || IS_FIRST_PART_TEXT(mimeinfo)) {
+               procmime_mimeinfo_free_all(mimeinfo);
                return;
        }
-#if 0 /* NEW COMPOSE GUI */
-       if (!compose->use_attach) {
-               GtkItemFactory *ifactory;
-               GtkWidget *menuitem;
+       if (IS_FIRST_PART_TEXT(child))
+               child = child->next;
 
-               ifactory = gtk_item_factory_from_widget(compose->menubar);
-               menuitem = gtk_item_factory_get_item(ifactory,
-                                                    "/Message/Attach");
-               gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),
-                                              TRUE);
-       }
-#endif
-       ainfo = g_new0(AttachInfo, 1);
-       ainfo->file = g_strdup(file);
+       infile = procmsg_get_message_file_path(msginfo);
 
-       if (cnttype == MIME_MESSAGE_RFC822) {
-               ainfo->content_type = g_strdup("message/rfc822");
-               ainfo->encoding = ENC_7BIT;
-               ainfo->name = g_strdup_printf(_("Message: %s"),
-                                             g_basename(file));
-       } else {
-               ainfo->content_type = procmime_get_mime_type(file);
-               if (!ainfo->content_type)
-                       ainfo->content_type =
-                               g_strdup("application/octet-stream");
-               ainfo->encoding = ENC_BASE64;
-               ainfo->name = g_strdup(g_basename(file));
+       while (child != NULL) {
+               if (child->children || child->mime_type == MIME_MULTIPART) {
+                       child = procmime_mimeinfo_next(child);
+                       continue;
+               }
+
+               outfile = procmime_get_tmp_file_name(child);
+               if (procmime_get_part(outfile, infile, child) < 0)
+                       g_warning(_("Can't get the part of multipart message."));
+               else
+                       compose_attach_append
+                               (compose, outfile,
+                                child->filename ? child->filename : child->name,
+                                child->content_type);
+
+               child = child->next;
        }
-       ainfo->size = size;
 
-       compose_attach_info(compose, ainfo, cnttype);
+       g_free(infile);
+       procmime_mimeinfo_free_all(mimeinfo);
 }
 
+#undef IS_FIRST_PART_TEXT
+
 #define GET_CHAR(pos, buf, len)                                                     \
 {                                                                           \
        if (text->use_wchar)                                                 \
-               len = wctomb(buf, (wchar_t)GTK_STEXT_INDEX(text, (pos)));     \
+               len = wctomb(buf, (wchar_t)GTK_STEXT_INDEX(text, (pos)));    \
        else {                                                               \
                buf[0] = GTK_STEXT_INDEX(text, (pos));                       \
                len = 1;                                                     \
        }                                                                    \
 }
 
+#define INDENT_CHARS   ">|#"
+#define SPACE_CHARS    " \t"
+
 static void compose_wrap_line(Compose *compose)
 {
        GtkSText *text = GTK_STEXT(compose->text);
@@ -1948,7 +2018,6 @@ static void compose_wrap_line(Compose *compose)
        gint line_pos, cur_pos;
        gint line_len, cur_len;
 
-
        gtk_stext_freeze(text);
 
        text_len = gtk_stext_get_length(text);
@@ -1977,7 +2046,7 @@ static void compose_wrap_line(Compose *compose)
                        }
                        line_end = 1;
                } else {
-                       if (ch_len == 1 && strchr(">:#", *cbuf))
+                       if (ch_len == 1 && strchr(INDENT_CHARS, *cbuf))
                                quoted = 1;
                        else if (ch_len != 1 || !isspace(*cbuf))
                                quoted = 0;
@@ -1999,7 +2068,8 @@ static void compose_wrap_line(Compose *compose)
                        }
                        line_end = 1;
                } else {
-                       if (line_end && ch_len == 1 && strchr(">:#", *cbuf))
+                       if (line_end && ch_len == 1 &&
+                           strchr(INDENT_CHARS, *cbuf))
                                goto compose_end; /* quoted part */
 
                        line_end = 0;
@@ -2096,29 +2166,104 @@ compose_end:
        gtk_stext_thaw(text);
 }
 
+#undef WRAP_DEBUG
+#ifdef WRAP_DEBUG
+/* Darko: used when I debug wrapping */
+void dump_text(GtkSText *text, int pos, int tlen, int breakoncr)
+{
+       gint i;
+       gchar ch;
+
+       printf("%d [", pos);
+       for (i = pos; i < tlen; i++) {
+               ch = GTK_STEXT_INDEX(text, i);
+               if (breakoncr && ch == '\n')
+                       break;
+               printf("%c", ch);
+       }
+       printf("]\n");
+}
+#endif
+
+typedef enum {
+       WAIT_FOR_SPACE,
+       WAIT_FOR_INDENT_CHAR,
+       WAIT_FOR_INDENT_CHAR_OR_SPACE
+} IndentState;
+
+/* return indent length, we allow:
+   > followed by spaces/tabs
+   | followed by spaces/tabs
+   uppercase characters immediately followed by >,
+   and the repeating sequences of the above */
 /* return indent length */
 static guint get_indent_length(GtkSText *text, guint start_pos, guint text_len)
 {
-       gint indent_len = 0;
-       gint i, ch_len;
+       guint i_len = 0;
+       guint i, ch_len, alnum_cnt = 0;
+       IndentState state = WAIT_FOR_INDENT_CHAR;
        gchar cbuf[MB_LEN_MAX];
+       gboolean is_space;
+       gboolean is_indent;
 
        for (i = start_pos; i < text_len; i++) {
                GET_CHAR(i, cbuf, ch_len);
                if (ch_len > 1)
                        break;
-               /* allow space, tab, > or | */
-               if (cbuf[0] != ' ' && cbuf[0] != '\t' &&
-                   cbuf[0] != '>' && cbuf[0] != '|')
+
+               if (cbuf[0] == '\n')
+                       break;
+
+               is_indent = strchr(INDENT_CHARS, cbuf[0]) ? TRUE : FALSE;
+               is_space = strchr(SPACE_CHARS, cbuf[0]) ? TRUE : FALSE;
+
+               switch (state) {
+               case WAIT_FOR_SPACE:
+                       if (is_space == FALSE)
+                               goto out;
+                       state = WAIT_FOR_INDENT_CHAR_OR_SPACE;
+                       break;
+               case WAIT_FOR_INDENT_CHAR_OR_SPACE:
+                       if (is_indent == FALSE && is_space == FALSE &&
+                           !isupper(cbuf[0]))
+                               goto out;
+                       if (is_space == TRUE) {
+                               alnum_cnt = 0;
+                               state = WAIT_FOR_INDENT_CHAR_OR_SPACE;
+                       } else if (is_indent == TRUE) {
+                               alnum_cnt = 0;
+                               state = WAIT_FOR_SPACE;
+                       } else {
+                               alnum_cnt++;
+                               state = WAIT_FOR_INDENT_CHAR;
+                       }
+                       break;
+               case WAIT_FOR_INDENT_CHAR:
+                       if (is_indent == FALSE && !isupper(cbuf[0]))
+                               goto out;
+                       if (is_indent == TRUE) {
+                               if (alnum_cnt > 0 && cbuf[0] != '>')
+                                       goto out;
+                               alnum_cnt = 0;
+                               state = WAIT_FOR_SPACE;
+                       } else {
+                               alnum_cnt++;
+                       }
                        break;
-               indent_len++;
+               }
+
+               i_len++;
        }
 
-       return indent_len;
+out:
+       if ((i_len > 0) && (state == WAIT_FOR_INDENT_CHAR))
+               i_len -= alnum_cnt;
+
+       return i_len;
 }
 
 /* insert quotation string when line was wrapped */
-static guint ins_quote(GtkSText *text, guint quote_len, guint indent_len,
+static guint ins_quote(GtkSText *text, guint indent_len,
                       guint prev_line_pos, guint text_len,
                       gchar *quote_fmt)
 {
@@ -2131,32 +2276,29 @@ static guint ins_quote(GtkSText *text, guint quote_len, guint indent_len,
                        gtk_stext_insert(text, NULL, NULL, NULL, &ch, 1);
                }
                ins_len = indent_len;
-       } else {
-               gtk_stext_insert(text, NULL, NULL, NULL, quote_fmt, quote_len);
-               ins_len = quote_len;
        }
 
        return ins_len;
 }
 
-#undef WRAP_DEBUG
-#ifdef WRAP_DEBUG
-/* Darko: used when I debug wrapping */
-void dump_text(GtkSText *text, int pos, int tlen, int breakoncr)
+/* check if we should join the next line */
+static gboolean join_next_line(GtkSText *text, guint start_pos, guint tlen,
+                              guint prev_ilen)
 {
-       gint i;
-       gchar ch;
+       guint indent_len, ch_len;
+       gboolean do_join = FALSE;
+       gchar cbuf[MB_LEN_MAX];
 
-       printf("%d [", pos);
-       for (i = pos; i < tlen; i++) {
-               ch = GTK_STEXT_INDEX(text, i);
-               if (breakoncr && ch == '\n')
-                       break;
-               printf("%c", ch);
+       indent_len = get_indent_length(text, start_pos, tlen);
+
+       if ((indent_len > 0) && (indent_len == prev_ilen)) {
+               GET_CHAR(start_pos + indent_len, cbuf, ch_len);
+               if (ch_len > 0 && (cbuf[0] != '\n'))
+                       do_join = TRUE;
        }
-       printf("]\n");
+
+       return do_join;
 }
-#endif
 
 static void compose_wrap_line_all(Compose *compose)
 {
@@ -2166,8 +2308,8 @@ static void compose_wrap_line_all(Compose *compose)
        gint line_len = 0, cur_len = 0;
        gint ch_len;
        gboolean is_new_line = TRUE, do_delete = FALSE;
-       guint qlen = 0, i_len = 0;
-       guint linewrap_quote = prefs_common.linewrap_quote;
+       guint i_len = 0;
+       gboolean linewrap_quote = TRUE;
        guint linewrap_len = prefs_common.linewrap_len;
        gchar *qfmt = prefs_common.quotemark;
        gchar cbuf[MB_LEN_MAX];
@@ -2182,19 +2324,13 @@ static void compose_wrap_line_all(Compose *compose)
        for (; cur_pos < tlen; cur_pos++) {
                /* mark position of new line - needed for quotation wrap */
                if (is_new_line) {
-                       if (linewrap_quote) {
-                               qlen = gtkut_text_str_compare
-                                       (text, cur_pos, tlen, qfmt);
-                               if (qlen)
-                                       i_len = get_indent_length
-                                               (text, cur_pos, tlen);
-                               else
-                                       i_len = 0;
-                       }
+                       if (linewrap_quote)
+                               i_len = get_indent_length(text, cur_pos, tlen);
+
                        is_new_line = FALSE;
                        p_pos = cur_pos;
 #ifdef WRAP_DEBUG
-                       printf("new line i_len=%d qlen=%d p_pos=", i_len, qlen);
+                       printf("new line i_len=%d p_pos=", i_len);
                        dump_text(text, p_pos, tlen, 1);
 #endif
                }
@@ -2222,35 +2358,29 @@ static void compose_wrap_line_all(Compose *compose)
                /* we have encountered line break */
                if (ch_len == 1 && *cbuf == '\n') {
                        gint clen;
-                       guint ilen;
                        gchar cb[MB_CUR_MAX];
 
+                       /* should we join the next line */
+                       if ((i_len != cur_len) && do_delete &&
+                           join_next_line(text, cur_pos + 1, tlen, i_len))
+                               do_delete = TRUE;
+                       else
+                               do_delete = FALSE;
+
 #ifdef WRAP_DEBUG
-                       printf("found CR at %d next line is ", cur_pos);
+                       printf("found CR at %d do_del is %d next line is ",
+                              cur_pos, do_delete);
                        dump_text(text, cur_pos + 1, tlen, 1);
 #endif
-                       /* if it's just quotation + newline skip it */
-                       if (i_len && (cur_pos + 1 < tlen)) {
-                               /* check if text at new line matches indent */
-                               ilen =  gtkut_text_str_compare_n
-                                       (text, cur_pos + 1, p_pos, i_len, tlen);
-                               if (cur_pos + ilen < tlen) {
-                                       GET_CHAR(cur_pos + ilen + 1, cb, clen);
-                                       /* no need to join the lines */
-                                       if (clen == 1 && cb[0] == '\n')
-                                               do_delete = FALSE;
-                               }
-                       /* if it's just newline skip it */
-                       } else if (do_delete && (cur_pos + 1 < tlen)) {
-                               GET_CHAR(cur_pos + 1, cb, clen);
-                               /* no need to join the lines */
-                               if (clen == 1 && cb[0] == '\n')
-                                       do_delete = FALSE;
-                       }
+
+                       /* skip delete if it is continuous URL */
+                       if (do_delete && (line_pos - p_pos <= i_len) &&
+                           gtkut_stext_is_uri_string(text, line_pos, tlen))
+                               do_delete = FALSE;
 
 #ifdef WRAP_DEBUG
-                       printf("qlen=%d l_len=%d wrap_len=%d do_del=%d\n",
-                               qlen, line_len, linewrap_len, do_delete);
+                       printf("l_len=%d wrap_len=%d do_del=%d\n",
+                               line_len, linewrap_len, do_delete);
 #endif
                        /* should we delete to perform smart wrapping */
                        if (line_len < linewrap_len && do_delete) {
@@ -2262,20 +2392,14 @@ static void compose_wrap_line_all(Compose *compose)
                                /* if text starts with quote fmt or with
                                   indent string, delete them */
                                if (i_len) {
-                                       ilen =  gtkut_text_str_compare_n
+                                       guint ilen;
+                                       ilen =  gtkut_stext_str_compare_n
                                                (text, cur_pos, p_pos, i_len,
                                                 tlen);
                                        if (ilen) {
-                                               gtk_stext_forward_delete(text,
-                                                                        ilen);
-                                               tlen -= ilen;
-                                       }
-                               } else if (qlen) {
-                                       if (gtkut_text_str_compare
-                                           (text, cur_pos, tlen, qfmt)) {
                                                gtk_stext_forward_delete
-                                                       (text, qlen);
-                                               tlen -= qlen;
+                                                       (text, ilen);
+                                               tlen -= ilen;
                                        }
                                }
 
@@ -2286,7 +2410,7 @@ static void compose_wrap_line_all(Compose *compose)
                                    ((clen > 1) || isalnum(cb[0]))) {
                                        gtk_stext_insert(text, NULL, NULL,
                                                        NULL, " ", 1);
-                                       /* gtk_text_compact_buffer(text); */
+                                       /* gtk_stext_compact_buffer(text); */
                                        tlen++;
                                }
 
@@ -2294,7 +2418,6 @@ static void compose_wrap_line_all(Compose *compose)
                                cur_pos = p_pos - 1;
                                line_pos = cur_pos;
                                line_len = cur_len = 0;
-                               qlen = 0;
                                do_delete = FALSE;
                                is_new_line = TRUE;
 #ifdef WRAP_DEBUG
@@ -2307,7 +2430,6 @@ static void compose_wrap_line_all(Compose *compose)
                        /* mark new line beginning */
                        line_pos = cur_pos + 1;
                        line_len = cur_len = 0;
-                       qlen = 0;
                        do_delete = FALSE;
                        is_new_line = TRUE;
                        continue;
@@ -2334,8 +2456,8 @@ static void compose_wrap_line_all(Compose *compose)
                        dump_text(text, line_pos, tlen, 1);
 #endif
                        /* force wrapping if it is one long word but not URL */
-                       if (p_pos + i_len == line_pos)
-                               if (!gtkut_text_is_uri_string
+                       if (line_pos - p_pos <= i_len)
+                               if (!gtkut_stext_is_uri_string
                                    (text, line_pos, tlen))
                                        line_pos = cur_pos - 1;
 #ifdef WRAP_DEBUG
@@ -2347,7 +2469,7 @@ static void compose_wrap_line_all(Compose *compose)
                        /* if next character is space delete it */
                         if (clen == 1 && isspace(*cbuf)) {
                                if (p_pos + i_len != line_pos ||
-                                   !gtkut_text_is_uri_string
+                                   !gtkut_stext_is_uri_string
                                        (text, line_pos, tlen)) {
                                        gtk_stext_set_point(text, line_pos);
                                        gtk_stext_backward_delete(text, 1);
@@ -2361,7 +2483,7 @@ static void compose_wrap_line_all(Compose *compose)
 
                        /* if it is URL at beginning of line don't wrap */
                        if (p_pos + i_len == line_pos &&
-                           gtkut_text_is_uri_string(text, line_pos, tlen)) {
+                           gtkut_stext_is_uri_string(text, line_pos, tlen)) {
 #ifdef WRAP_DEBUG
                                printf("found URL at ");
                                dump_text(text, line_pos, tlen, 1);
@@ -2381,7 +2503,10 @@ static void compose_wrap_line_all(Compose *compose)
                        is_new_line = TRUE;
                        line_len = 0;
                        cur_len = 0;
-                       do_delete = TRUE;
+                       if (i_len)
+                               do_delete = TRUE;
+                       else
+                               do_delete = FALSE;
 #ifdef WRAP_DEBUG
                        printf("after CR insert ");
                        dump_text(text, line_pos, tlen, 1);
@@ -2389,16 +2514,16 @@ static void compose_wrap_line_all(Compose *compose)
 #endif
 
                        /* should we insert quotation ? */
-                       if (linewrap_quote && qlen) {
+                       if (linewrap_quote && i_len) {
                                /* only if line is not already quoted  */
-                               if (!gtkut_text_str_compare
+                               if (!gtkut_stext_str_compare
                                        (text, line_pos, tlen, qfmt)) {
                                        guint ins_len;
 
                                        if (line_pos - p_pos > i_len) {
                                                ins_len = ins_quote
-                                                       (text, qlen, i_len,
-                                                        p_pos, tlen, qfmt);
+                                                       (text, i_len, p_pos,
+                                                        tlen, qfmt);
 
                                                /* gtk_stext_compact_buffer(text); */
                                                tlen += ins_len;
@@ -2422,6 +2547,7 @@ static void compose_wrap_line_all(Compose *compose)
 
        gtk_stext_thaw(text);
 }
+
 #undef GET_CHAR
 
 static void compose_set_title(Compose *compose)
@@ -2508,12 +2634,38 @@ gboolean compose_check_for_valid_recipient(Compose *compose) {
        return recipient_found;
 }
 
+static gboolean compose_check_entries(Compose *compose, gboolean check_subject)
+{
+       gchar *str;
+
+       if (compose_check_for_valid_recipient(compose) == FALSE) {
+               alertpanel_error(_("Recipient is not specified."));
+               return FALSE;
+       }
+
+       str = gtk_entry_get_text(GTK_ENTRY(compose->subject_entry));
+       if (*str == '\0' && check_subject == TRUE) {
+               AlertValue aval;
+
+               aval = alertpanel(_("Send"),
+                                 _("Subject is empty. Send it anyway?"),
+                                 _("Yes"), _("No"), NULL);
+               if (aval != G_ALERTDEFAULT)
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
 gint compose_send(Compose *compose)
 {
        gint msgnum;
        FolderItem *folder;
        gint val;
 
+       if (compose_check_entries(compose, TRUE) == FALSE)
+               return -1;
+
        val = compose_queue(compose, &msgnum, &folder);
        if (val) {
                alertpanel_error(_("Could not queue message for sending"));
@@ -2521,10 +2673,9 @@ gint compose_send(Compose *compose)
        }
        
        val = procmsg_send_message_queue(folder_item_fetch_msg(folder, msgnum));
-       if(!val) {
-               folder_item_remove_msg(folder, msgnum);
-               folderview_update_item(folder, TRUE);
-       }
+
+       folder_item_remove_msg(folder, msgnum);
+       folderview_update_item(folder, TRUE);
 
        return val;
 }
@@ -2543,8 +2694,7 @@ gint compose_send(Compose *compose)
 
        lock = TRUE;
 
-       if(!compose_check_for_valid_recipient(compose)) {
-               alertpanel_error(_("Recipient is not specified."));
+       if (compose_check_entries(compose, TRUE) == FALSE) {
                lock = FALSE;
                return 1;
        }
@@ -2635,13 +2785,18 @@ gint compose_send(Compose *compose)
                                folderview_update_item
                                        (compose->targetinfo->folder, TRUE);
                }
-       }
+               /* save message to outbox */
+               if (prefs_common.savemsg) {
+                       FolderItem *outbox;
 
-       /* save message to outbox */
-       if (ok == 0 && prefs_common.savemsg) {
-               if (compose_save_to_outbox(compose, tmp) < 0)
-                       alertpanel_error
-                               (_("Can't save the message to outbox."));
+                       outbox = account_get_special_folder
+                               (compose->account, F_OUTBOX);
+                       if (procmsg_save_to_outbox(outbox, tmp, FALSE) < 0)
+                               alertpanel_error
+                                       (_("Can't save the message to outbox."));
+                       else
+                               folderview_update_item(outbox, TRUE);
+               }
        }
 
        unlink(tmp);
@@ -2745,12 +2900,12 @@ static gint compose_bounce_write_to_file(Compose *compose, const gchar *file)
        size_t len;
        gchar buf[BUFFSIZE];
 
-       if ((fp = fopen(compose->bounce_filename, "r")) == NULL) {
+       if ((fp = fopen(compose->bounce_filename, "rb")) == NULL) {
                FILE_OP_ERROR(file, "fopen");
                return -1;
        }
 
-       if ((fdest = fopen(file, "w")) == NULL) {
+       if ((fdest = fopen(file, "wb")) == NULL) {
                FILE_OP_ERROR(file, "fopen");
                fclose(fp);
                return -1;
@@ -2773,20 +2928,24 @@ static gint compose_bounce_write_to_file(Compose *compose, const gchar *file)
                if (fputs(buf, fdest) == -1)
                        goto error;
 
-               if (g_strncasecmp(buf, "From:", strlen("From:")) == 0) {
-                       fputs(" (by way of ", fdest);
-                       if (compose->account->name
-                           && *compose->account->name) {
-                               compose_convert_header
-                                       (buf, sizeof(buf),
-                                        compose->account->name,
-                                        strlen("From: "));
-                               fprintf(fdest, "%s <%s>",
-                                       buf, compose->account->address);
-                       } else
-                               fprintf(fdest, "%s",
-                                       compose->account->address);
-                       fputs(")", fdest);
+               if (!prefs_common.bounce_keep_from) {
+                       if (g_strncasecmp(buf, "From:",
+                                         strlen("From:")) == 0) {
+                               fputs(" (by way of ", fdest);
+                               if (compose->account->name
+                                   && *compose->account->name) {
+                                       compose_convert_header
+                                               (buf, sizeof(buf),
+                                                compose->account->name,
+                                                strlen("From: "));
+                                       fprintf(fdest, "%s <%s>",
+                                               buf,
+                                               compose->account->address);
+                               } else
+                                       fprintf(fdest, "%s",
+                                               compose->account->address);
+                               fputs(")", fdest);
+                       }
                }
 
                if (fputs("\n", fdest) == -1)
@@ -2811,6 +2970,46 @@ static gint compose_bounce_write_to_file(Compose *compose, const gchar *file)
        return -1;
 }
 
+
+#ifdef USE_GPGME
+/*
+ * interfaces to rfc2015 to keep out the prefs stuff there.
+ * returns 0 on success and -1 on error. */
+static int compose_create_signers_list (Compose *compose, GSList **pkey_list)
+{
+       const char *keyid = NULL;
+       GSList *key_list;
+
+       switch (compose->account->sign_key) {
+       case SIGN_KEY_DEFAULT:
+               *pkey_list = NULL;
+               return 0;               /* nothing to do */
+
+       case SIGN_KEY_BY_FROM:
+               keyid = compose->account->address;
+               break;
+
+       case SIGN_KEY_CUSTOM:
+               keyid = compose->account->sign_key_id;
+               break;
+
+       default:
+               g_assert_not_reached ();
+       }
+
+       key_list = rfc2015_create_signers_list(keyid);
+
+       if (!key_list) {
+           alertpanel_error("Could not find any key associated with currently "
+                               "selected keyid `%s'!", keyid);
+           return -1;
+       }
+       
+       *pkey_list = key_list;
+       return 0;
+}
+#endif /* USE_GPGME */
+
 static gint compose_write_to_file(Compose *compose, const gchar *file,
                                  gboolean is_draft)
 {
@@ -2821,7 +3020,7 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
        const gchar *out_codeset;
        EncodingType encoding;
 
-       if ((fp = fopen(file, "w")) == NULL) {
+       if ((fp = fopen(file, "wb")) == NULL) {
                FILE_OP_ERROR(file, "fopen");
                return -1;
        }
@@ -2858,11 +3057,20 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
 
                buf = conv_codeset_strdup(chars, src_codeset, out_codeset);
                if (!buf) {
-                       g_free(chars);
-                       fclose(fp);
-                       unlink(file);
-                       alertpanel_error(_("Can't convert the codeset of the message."));
-                       return -1;
+                       AlertValue aval;
+
+                       aval = alertpanel
+                               (_("Error"),
+                                _("Can't convert the character encoding of the message.\n"
+                                  "Send it anyway?"), _("Yes"), _("+No"), NULL);
+                       if (aval != G_ALERTDEFAULT) {
+                               g_free(chars);
+                               fclose(fp);
+                               unlink(file);
+                               return -1;
+                       } else {
+                               buf = g_strdup(chars);
+                       }
                }
        }
        g_free(chars);
@@ -2926,13 +3134,17 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
 
 #if USE_GPGME
        if (compose->use_signing) {
-               if (rfc2015_sign(file, compose->account) < 0) {
+               GSList *key_list;
+               
+               if (compose_create_signers_list(compose, &key_list) == -1 ||
+                       rfc2015_sign(file, key_list) < 0) {
+                   
                        unlink(file);
                        return -1;
                }
        }
        if (compose->use_encryption) {
-               if (rfc2015_encrypt(file, compose->to_list) < 0) {
+               if (rfc2015_encrypt(file, compose->to_list, compose->account->ascii_armored) < 0) {
                        unlink(file);
                        return -1;
                }
@@ -2948,7 +3160,7 @@ static gint compose_write_body_to_file(Compose *compose, const gchar *file)
        size_t len;
        gchar *chars;
 
-       if ((fp = fopen(file, "w")) == NULL) {
+       if ((fp = fopen(file, "wb")) == NULL) {
                FILE_OP_ERROR(file, "fopen");
                return -1;
        }
@@ -2981,43 +3193,6 @@ static gint compose_write_body_to_file(Compose *compose, const gchar *file)
        return 0;
 }
 
-static gint compose_save_to_outbox(Compose *compose, const gchar *file)
-{
-       FolderItem *outbox;
-       gchar *path;
-       gint num;
-       FILE *fp;
-
-       debug_print(_("saving sent message...\n"));
-
-       outbox = folder_get_default_outbox();
-       path = folder_item_get_path(outbox);
-       if (!is_dir_exist(path))
-               make_dir_hier(path);
-
-       folder_item_scan(outbox);
-       if ((num = folder_item_add_msg(outbox, file, FALSE)) < 0) {
-               g_free(path);
-               g_warning(_("can't save message\n"));
-               return -1;
-       }
-
-       if ((fp = procmsg_open_mark_file(path, TRUE)) == NULL)
-               g_warning(_("can't open mark file\n"));
-       else {
-               MsgInfo newmsginfo;
-
-               newmsginfo.msgnum = num;
-               newmsginfo.flags.perm_flags = 0;
-               newmsginfo.flags.tmp_flags = 0;
-               procmsg_write_flags(&newmsginfo, fp);
-               fclose(fp);
-       }
-       g_free(path);
-
-       return 0;
-}
-
 static gint compose_remove_reedit_target(Compose *compose)
 {
        FolderItem *item;
@@ -3041,8 +3216,11 @@ static gint compose_remove_reedit_target(Compose *compose)
        return 0;
 }
 
-
 static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
+{
+       return compose_queue_sub (compose, msgnum, item, FALSE);
+}
+static gint compose_queue_sub(Compose *compose, gint *msgnum, FolderItem **item, gboolean check_subject)
 {
        FolderItem *queue;
        gchar *tmp, *tmp2, *queue_path;
@@ -3050,6 +3228,7 @@ static gint compose_queue(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;
        
@@ -3059,12 +3238,11 @@ static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
 
         lock = TRUE;
        
-        if(!compose_check_for_valid_recipient(compose)) {
-                alertpanel_error(_("Recipient is not specified."));
+       if (compose_check_entries(compose, check_subject) == FALSE) {
                 lock = FALSE;
                 return -1;
-        }
-                                                                       
+       }
+
        if (!compose->to_list && !compose->newsgroup_list) {
                g_warning(_("can't get recipient list."));
                lock = FALSE;
@@ -3119,13 +3297,13 @@ static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
 
        /* add queue header */
        tmp = g_strdup_printf("%s%cqueue.%d", g_get_tmp_dir(),
-                                     G_DIR_SEPARATOR, (gint)compose);
-       if ((fp = fopen(tmp, "w")) == NULL) {
+                             G_DIR_SEPARATOR, (gint)compose);
+       if ((fp = fopen(tmp, "wb")) == NULL) {
                FILE_OP_ERROR(tmp, "fopen");
                g_free(tmp);
                return -1;
        }
-       if ((src_fp = fopen(tmp2, "r")) == NULL) {
+       if ((src_fp = fopen(tmp2, "rb")) == NULL) {
                FILE_OP_ERROR(tmp2, "fopen");
                fclose(fp);
                unlink(tmp);
@@ -3217,10 +3395,8 @@ static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
                g_free(tmp2);
                return -1;
        }
-                                               
-       /* queue message */
-       queue = folder_get_default_queue();
 
+       queue = account_get_special_folder(compose->account, F_QUEUE);
        folder_item_scan(queue);
        queue_path = folder_item_get_path(queue);
        if (!is_dir_exist(queue_path))
@@ -3245,19 +3421,7 @@ static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
                                (compose->targetinfo->folder, TRUE);
        }
 
-       if ((fp = procmsg_open_mark_file(queue_path, TRUE)) == NULL)
-               g_warning(_("can't open mark file\n"));
-       else {
-               MsgInfo newmsginfo;
-
-               newmsginfo.msgnum = num;
-               newmsginfo.flags.perm_flags = 0;
-               newmsginfo.flags.tmp_flags = 0;
-               procmsg_write_flags(&newmsginfo, fp);
-               fclose(fp);
-       }
-       g_free(queue_path);
-
+       procmsg_add_flags(queue, num, flag);
        folder_item_scan(queue);
        folderview_update_item(queue, TRUE);
 
@@ -3280,7 +3444,10 @@ static void compose_write_attach(Compose *compose, FILE *fp)
 
        for (row = 0; (ainfo = gtk_clist_get_row_data(clist, row)) != NULL;
             row++) {
-               if ((attach_fp = fopen(ainfo->file, "r")) == NULL) {
+               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;
                }
@@ -3303,15 +3470,19 @@ static void compose_write_attach(Compose *compose, FILE *fp)
                fprintf(fp, "Content-Transfer-Encoding: %s\n\n",
                        procmime_get_encoding_str(ainfo->encoding));
 
-               if (ainfo->encoding == ENC_7BIT) {
-                       gchar buf[BUFFSIZE];
+               switch (ainfo->encoding) {
+
+               case ENC_7BIT:
+               case ENC_8BIT:
+                       /* if (ainfo->encoding == ENC_7BIT) { */
 
                        while (fgets(buf, sizeof(buf), attach_fp) != NULL) {
                                strcrchomp(buf);
                                fputs(buf, fp);
                        }
-               } else {
-                       gchar inbuf[B64_LINE_SIZE], outbuf[B64_BUFFSIZE];
+                       break;
+                       /* } else { */
+               case ENC_BASE64:
 
                        while ((len = fread(inbuf, sizeof(gchar),
                                            B64_LINE_SIZE, attach_fp))
@@ -3325,6 +3496,7 @@ static void compose_write_attach(Compose *compose, FILE *fp)
                                fputs(outbuf, fp);
                                fputc('\n', fp);
                        }
+                       break;
                }
 
                fclose(attach_fp);
@@ -3702,7 +3874,6 @@ static void compose_generate_msgid(Compose *compose, gchar *buf, gint len)
        g_free(addr);
 }
 
-
 static void compose_add_entry_field(GtkWidget *table, GtkWidget **hbox,
                                    GtkWidget **entry, gint *count,
                                    const gchar *label_str,
@@ -3778,6 +3949,7 @@ static void compose_create_header_entry(Compose *compose)
 
         gtk_signal_connect(GTK_OBJECT(entry), "key-press-event", GTK_SIGNAL_FUNC(compose_headerentry_key_press_event_cb), headerentry);
        gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(compose_headerentry_changed_cb), headerentry);
+       gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(text_activated), compose);
 
        address_completion_register_entry(GTK_ENTRY(entry));
 
@@ -3803,6 +3975,7 @@ static void compose_add_header_entry(Compose *compose, gchar *header, gchar *tex
 static GtkWidget *compose_create_header(Compose *compose) 
 {
        GtkWidget *label;
+       GtkWidget *hbox;
        GtkWidget *from_optmenu_hbox;
 #if 0 /* NEW COMPOSE GUI */
        GtkWidget *to_entry;
@@ -3812,7 +3985,6 @@ static GtkWidget *compose_create_header(Compose *compose)
 #endif
        GtkWidget *header_scrolledwin;
        GtkWidget *header_table;
-       GtkWidget *subject_entry;
 #if 0 /* NEW COMPOSE GUI */
        GtkWidget *cc_entry;
        GtkWidget *cc_hbox;
@@ -3823,7 +3995,6 @@ static GtkWidget *compose_create_header(Compose *compose)
        GtkWidget *followup_entry;
        GtkWidget *followup_hbox;
 #endif
-       GtkWidget *hbox;
 
        gint count = 0;
 
@@ -3836,6 +4007,7 @@ static GtkWidget *compose_create_header(Compose *compose)
        gtk_widget_show(header_table);
        gtk_container_set_border_width(GTK_CONTAINER(header_table), 2);
        gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(header_scrolledwin), header_table);
+       gtk_viewport_set_shadow_type(GTK_VIEWPORT(GTK_BIN(header_scrolledwin)->child), GTK_SHADOW_ETCHED_IN);
        count = 0;
 
        /* option menu for selecting accounts */
@@ -3852,10 +4024,6 @@ static GtkWidget *compose_create_header(Compose *compose)
 #endif
        count++;
 
-       /* Subject */
-       compose_add_entry_field(header_table, &hbox, &subject_entry, &count,
-                               "Subject:", FALSE);
-
        compose->header_table = header_table;
        compose->header_list = NULL;
        compose->header_nextrow = count;
@@ -3926,7 +4094,6 @@ static GtkWidget *compose_create_header(Compose *compose)
        compose->newsgroups_hbox  = newsgroups_hbox;
        compose->newsgroups_entry = newsgroups_entry;
 #endif
-       compose->subject_entry    = subject_entry;
 #if 0 /* NEW COMPOSE GUI */
        compose->cc_hbox          = cc_hbox;
        compose->cc_entry         = cc_entry;
@@ -3943,12 +4110,16 @@ static GtkWidget *compose_create_header(Compose *compose)
 
 GtkWidget *compose_create_attach(Compose *compose)
 {
-       gchar *titles[] = {_("MIME type"), _("Size"), _("Name")};
+       gchar *titles[N_ATTACH_COLS];
        gint i;
 
        GtkWidget *attach_scrwin;
        GtkWidget *attach_clist;
 
+       titles[COL_MIMETYPE] = _("MIME type");
+       titles[COL_SIZE]     = _("Size");
+       titles[COL_NAME]     = _("Name");
+
        /* attachment list */
        attach_scrwin = gtk_scrolled_window_new(NULL, NULL);
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(attach_scrwin),
@@ -4013,7 +4184,9 @@ static GtkWidget *compose_create_others(Compose *compose)
        savemsg_checkbtn = gtk_check_button_new_with_label(_("Save Message to "));
        gtk_widget_show(savemsg_checkbtn);
        gtk_table_attach(GTK_TABLE(table), savemsg_checkbtn, 0, 1, rowcount, rowcount + 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 0, 0);
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(savemsg_checkbtn), prefs_common.savemsg);
+       if(folder_get_default_outbox()) {
+               gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(savemsg_checkbtn), prefs_common.savemsg);
+       }
        gtk_signal_connect(GTK_OBJECT(savemsg_checkbtn), "toggled",
                            GTK_SIGNAL_FUNC(compose_savemsg_checkbtn_cb), compose);
 
@@ -4021,9 +4194,11 @@ static GtkWidget *compose_create_others(Compose *compose)
        gtk_widget_show(savemsg_entry);
        gtk_table_attach_defaults(GTK_TABLE(table), savemsg_entry, 1, 2, rowcount, rowcount + 1);
        gtk_editable_set_editable(GTK_EDITABLE(savemsg_entry), prefs_common.savemsg);
-       folderidentifier = folder_item_get_identifier(folder_get_default_outbox());
-       gtk_entry_set_text(GTK_ENTRY(savemsg_entry), folderidentifier);
-       g_free(folderidentifier);
+       if(folder_get_default_outbox()) {
+               folderidentifier = folder_item_get_identifier(folder_get_default_outbox());
+               gtk_entry_set_text(GTK_ENTRY(savemsg_entry), folderidentifier);
+               g_free(folderidentifier);
+       }
 
        savemsg_select = gtk_button_new_with_label (_("Select ..."));
        gtk_widget_show (savemsg_select);
@@ -4051,7 +4226,7 @@ static void compose_savemsg_select_cb(GtkWidget *widget, Compose *compose)
        FolderItem *dest;
        gchar * path;
 
-       dest = foldersel_folder_sel(NULL, NULL);
+       dest = foldersel_folder_sel(NULL, FOLDER_SEL_COPY, NULL);
        if (!dest) return;
 
        path = folder_item_get_identifier(dest);
@@ -4072,8 +4247,11 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
 
        GtkWidget *vbox2;
 
-       GtkWidget *table_vbox;
-
+       GtkWidget *label;
+       GtkWidget *subject_hbox;
+       GtkWidget *subject_frame;
+       GtkWidget *subject_entry;
+       GtkWidget *subject;
        GtkWidget *paned;
 
        GtkWidget *edit_vbox;
@@ -4086,6 +4264,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
 
        UndoMain *undostruct;
 
+       gchar *titles[N_ATTACH_COLS];
        guint n_menu_entries;
        GtkStyle  *style, *new_style;
        GdkColormap *cmap;
@@ -4103,11 +4282,17 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
         GtkPspell * gtkpspell = NULL;
 #endif
 
+       static GdkGeometry geometry;
+
        g_return_val_if_fail(account != NULL, NULL);
 
        debug_print(_("Creating compose window...\n"));
        compose = g_new0(Compose, 1);
 
+       titles[COL_MIMETYPE] = _("MIME type");
+       titles[COL_SIZE]     = _("Size");
+       titles[COL_NAME]     = _("Name");
+
        compose->account = account;
        compose->orig_account = account;
 
@@ -4115,14 +4300,19 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
        gtk_widget_set_usize(window, -1, prefs_common.compose_height);
        gtk_window_set_wmclass(GTK_WINDOW(window), "compose window", "Sylpheed");
+
+       if (!geometry.max_width) {
+               geometry.max_width = gdk_screen_width();
+               geometry.max_height = gdk_screen_height();
+       }
+       gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL,
+                                     &geometry, GDK_HINT_MAX_SIZE);
+
        gtk_signal_connect(GTK_OBJECT(window), "delete_event",
                           GTK_SIGNAL_FUNC(compose_delete_cb), compose);
        gtk_signal_connect(GTK_OBJECT(window), "destroy",
                           GTK_SIGNAL_FUNC(compose_destroy_cb), compose);
-       gtk_signal_connect(GTK_OBJECT(window), "focus_in_event",
-                          GTK_SIGNAL_FUNC(manage_window_focus_in), NULL);
-       gtk_signal_connect(GTK_OBJECT(window), "focus_out_event",
-                          GTK_SIGNAL_FUNC(manage_window_focus_out), NULL);
+       MANAGE_WINDOW_SIGNALS_CONNECT(window);
        gtk_widget_realize(window);
 
        gtkut_widget_set_composer_icon(window);
@@ -4143,15 +4333,10 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        vbox2 = gtk_vbox_new(FALSE, 2);
        gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
        gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
-
-       table_vbox = gtk_vbox_new(FALSE, 0);
-       gtk_box_pack_start(GTK_BOX(vbox2), table_vbox, FALSE, TRUE, 0);
-       gtk_container_set_border_width(GTK_CONTAINER(table_vbox),
-                                      BORDER_WIDTH * 2);
-
+       
        /* Notebook */
        notebook = gtk_notebook_new();
-       gtk_widget_set_usize(notebook, -1, 180);
+       gtk_widget_set_usize(notebook, -1, 130);
        gtk_widget_show(notebook);
 
        /* header labels and entries */
@@ -4161,11 +4346,37 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        /* Others Tab */
        gtk_notebook_append_page(GTK_NOTEBOOK(notebook), compose_create_others(compose), gtk_label_new(_("Others")));
 
+       /* Subject */
+       subject_hbox = gtk_hbox_new(FALSE, 0);
+       gtk_widget_show(subject_hbox);
+
+       subject_frame = gtk_frame_new(NULL);
+       gtk_frame_set_shadow_type(GTK_FRAME(subject_frame), GTK_SHADOW_OUT);
+       gtk_box_pack_start(GTK_BOX(subject_hbox), subject_frame, TRUE, TRUE, BORDER_WIDTH+1);
+       gtk_widget_show(subject_frame);
+
+       subject = gtk_hbox_new(FALSE, 0);
+       gtk_container_set_border_width(GTK_CONTAINER(subject), BORDER_WIDTH);
+       gtk_widget_show(subject);
+
+       label = gtk_label_new(_("Subject:"));
+       gtk_box_pack_start(GTK_BOX(subject), label, FALSE, FALSE, 4);
+       gtk_widget_show(label);
+
+       subject_entry = gtk_entry_new();
+       gtk_box_pack_start(GTK_BOX(subject), subject_entry, TRUE, TRUE, 2);
+       gtk_signal_connect(GTK_OBJECT(subject_entry), "activate", GTK_SIGNAL_FUNC(text_activated), compose);
+       gtk_widget_show(subject_entry);
+       compose->subject_entry = subject_entry;
+       gtk_container_add(GTK_CONTAINER(subject_frame), subject);
+       
        edit_vbox = gtk_vbox_new(FALSE, 0);
 #if 0 /* NEW COMPOSE GUI */
        gtk_box_pack_start(GTK_BOX(vbox2), edit_vbox, TRUE, TRUE, 0);
 #endif
 
+       gtk_box_pack_start(GTK_BOX(edit_vbox), subject_hbox, FALSE, FALSE, 0);
+
        /* ruler */
        ruler_hbox = gtk_hbox_new(FALSE, 0);
        gtk_box_pack_start(GTK_BOX(edit_vbox), ruler_hbox, FALSE, FALSE, 0);
@@ -4191,7 +4402,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        gtk_stext_set_editable(GTK_STEXT(text), TRUE);
 
        if (prefs_common.block_cursor) {
-               GTK_STEXT(text)->cursor_type = STEXT_CURSOR_BLOCK;
+               GTK_STEXT(text)->cursor_type = GTK_STEXT_CURSOR_BLOCK;
        }
        
        if (prefs_common.smart_wrapping) {      
@@ -4205,9 +4416,11 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
                           GTK_SIGNAL_FUNC(compose_changed_cb), compose);
        gtk_signal_connect(GTK_OBJECT(text), "grab_focus",
                           GTK_SIGNAL_FUNC(compose_grab_focus_cb), compose);
+       gtk_signal_connect(GTK_OBJECT(text), "activate",
+                          GTK_SIGNAL_FUNC(text_activated), compose);
        gtk_signal_connect_after(GTK_OBJECT(text), "button_press_event",
                                 GTK_SIGNAL_FUNC(compose_button_press_cb),
-                                compose);
+                                edit_vbox);
 #if 0
        gtk_signal_connect_after(GTK_OBJECT(text), "key_press_event",
                                 GTK_SIGNAL_FUNC(compose_key_press_cb),
@@ -4223,23 +4436,12 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        gtk_signal_connect(GTK_OBJECT(text), "drag_data_received",
                           GTK_SIGNAL_FUNC(compose_insert_drag_received_cb),
                           compose);
-#if USE_PSPELL
-        if (prefs_common.enable_pspell) {
-               gtkpspell = gtkpspell_new_with_config(gtkpspellconfig,
-                                                     prefs_common.pspell_path,
-                                                     prefs_common.dictionary,
-                                                     PSPELL_FASTMODE,
-                                                     conv_get_current_charset_str());
-               if (gtkpspell == NULL)
-                       prefs_common.enable_pspell = FALSE;
-               else
-                       gtkpspell_attach(gtkpspell, GTK_STEXT(text));
-        }
-#endif
        gtk_widget_show_all(vbox);
 
        /* pane between attach clist and text */
        paned = gtk_vpaned_new();
+       gtk_paned_set_gutter_size(GTK_PANED(paned), 12);
+       gtk_paned_set_handle_size(GTK_PANED(paned), 12);
        gtk_container_add(GTK_CONTAINER(vbox2), paned);
        gtk_paned_add1(GTK_PANED(paned), notebook);
        gtk_paned_add2(GTK_PANED(paned), edit_vbox);
@@ -4247,7 +4449,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
 
        style = gtk_widget_get_style(text);
 
-       /* workaround for the slow down of GtkText when using Pixmap theme */
+       /* workaround for the slow down of GtkSText when using Pixmap theme */
        if (style->engine) {
                GtkThemeEngine *engine;
 
@@ -4298,8 +4500,19 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        menu_set_sensitive(ifactory, "/Edit/Undo", FALSE);
        menu_set_sensitive(ifactory, "/Edit/Redo", FALSE);
 
-       tmpl_menu = gtk_item_factory_get_item(ifactory, "/Tool/Template");
+       tmpl_menu = gtk_item_factory_get_item(ifactory, "/Tools/Template");
 #if 0 /* NEW COMPOSE GUI */
+       gtk_widget_hide(bcc_hbox);
+       gtk_widget_hide(bcc_entry);
+       gtk_widget_hide(reply_hbox);
+       gtk_widget_hide(reply_entry);
+       gtk_widget_hide(followup_hbox);
+       gtk_widget_hide(followup_entry);
+       gtk_widget_hide(ruler_hbox);
+       gtk_table_set_row_spacing(GTK_TABLE(table), 4, 0);
+       gtk_table_set_row_spacing(GTK_TABLE(table), 5, 0);
+       gtk_table_set_row_spacing(GTK_TABLE(table), 6, 0);
+
        if (account->protocol == A_NNTP) {
                gtk_widget_hide(to_hbox);
                gtk_widget_hide(to_entry);
@@ -4311,28 +4524,16 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
                gtk_widget_hide(newsgroups_hbox);
                gtk_widget_hide(newsgroups_entry);
                gtk_table_set_row_spacing(GTK_TABLE(table), 2, 0);
-
-               menu_set_sensitive(ifactory, "/Message/Followup to", FALSE);
+               menu_set_sensitive(ifactory, "/View/Followup to", FALSE);
        }
 #endif
 
-       switch (prefs_common.toolbar_style) {
-       case TOOLBAR_NONE:
-               gtk_widget_hide(handlebox);
-               break;
-       case TOOLBAR_ICON:
-               gtk_toolbar_set_style(GTK_TOOLBAR(compose->toolbar),
-                                     GTK_TOOLBAR_ICONS);
-               break;
-       case TOOLBAR_TEXT:
-               gtk_toolbar_set_style(GTK_TOOLBAR(compose->toolbar),
-                                     GTK_TOOLBAR_TEXT);
-               break;
-       case TOOLBAR_BOTH:
-               gtk_toolbar_set_style(GTK_TOOLBAR(compose->toolbar),
-                                     GTK_TOOLBAR_BOTH);
-               break;
-       }
+       update_compose_actions_menu(ifactory, "/Tools/Actions", compose);
+
+
+       undostruct = undo_init(text);
+       undo_set_change_state_func(undostruct, &compose_undo_state_changed,
+                                  menubar);
 
        gtk_widget_show(window);
 
@@ -4345,8 +4546,6 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
 
        compose->vbox2         = vbox2;
 
-       compose->table_vbox       = table_vbox;
-
        compose->paned = paned;
 
        compose->edit_vbox     = edit_vbox;
@@ -4395,6 +4594,36 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        compose->exteditor_tag     = -1;
 
        compose->bounce_filename = NULL;
+       compose->undostruct = undostruct;
+#if USE_PSPELL
+       
+       menu_set_sensitive(ifactory, "/Spelling", FALSE);
+        if (prefs_common.enable_pspell) {
+               gtkpspell = gtkpspell_new((const gchar*)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 (!gtkpspell) {
+                       alertpanel_error(_("Spell checker could not be started.\n%s"), gtkpspellcheckers->error_message);
+                       gtkpspell_checkers_reset_error();
+               } else {
+
+                       GtkWidget *menuitem;
+
+                       if (!gtkpspell_set_sug_mode(gtkpspell, prefs_common.pspell_sugmode)) {
+                               debug_print(_("Pspell: could not set suggestion mode %s"),
+                                   gtkpspellcheckers->error_message);
+                               gtkpspell_checkers_reset_error();
+                       }
+
+                       menuitem = gtk_item_factory_get_item(ifactory, "/Spelling/Spelling Configuration");
+                       gtkpspell_populate_submenu(gtkpspell, menuitem);
+                       menu_set_sensitive(ifactory, "/Spelling", TRUE);
+                       }
+        }
+#endif
 
        compose_set_title(compose);
 
@@ -4408,18 +4637,13 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
         compose->gtkpspell      = gtkpspell;
 #endif
 
-       undostruct = undo_init(text);
-
-       compose->undostruct = undostruct;
-       undo_set_undo_change_funct(undostruct, &compose_set_undo, GTK_WIDGET(compose->menubar));
-
 #if 0 /* NEW COMPOSE GUI */
        if (account->protocol != A_NNTP) {
-               menuitem = gtk_item_factory_get_item(ifactory, "/Message/To");
+               menuitem = gtk_item_factory_get_item(ifactory, "/View/To");
                gtk_check_menu_item_set_active
                        (GTK_CHECK_MENU_ITEM(menuitem), TRUE);
                gtk_widget_set_sensitive(menuitem, FALSE);
-               menuitem = gtk_item_factory_get_item(ifactory, "/Message/Cc");
+               menuitem = gtk_item_factory_get_item(ifactory, "/View/Cc");
                gtk_check_menu_item_set_active
                        (GTK_CHECK_MENU_ITEM(menuitem), TRUE);
                gtk_widget_set_sensitive(menuitem, FALSE);
@@ -4430,7 +4654,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
 #if 0 /* NEW COMPOSE GUI */
                compose->use_cc = TRUE;
                gtk_entry_set_text(GTK_ENTRY(cc_entry), account->auto_cc);
-               menuitem = gtk_item_factory_get_item(ifactory, "/Message/Cc");
+               menuitem = gtk_item_factory_get_item(ifactory, "/View/Cc");
                gtk_check_menu_item_set_active
                        (GTK_CHECK_MENU_ITEM(menuitem), TRUE);
 #endif
@@ -4438,8 +4662,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        if (account->set_autobcc) {
                compose_entry_append(compose, account->auto_bcc, COMPOSE_BCC);
 #if 0 /* NEW COMPOSE GUI */
-               compose->use_bcc = TRUE;
-               menuitem = gtk_item_factory_get_item(ifactory, "/Message/Bcc");
+               menuitem = gtk_item_factory_get_item(ifactory, "/View/Bcc");
                gtk_check_menu_item_set_active
                        (GTK_CHECK_MENU_ITEM(menuitem), TRUE);
                if (account->auto_bcc && mode != COMPOSE_REEDIT)
@@ -4452,7 +4675,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
 #if 0 /* NEW COMPOSE GUI */
                compose->use_replyto = TRUE;
                menuitem = gtk_item_factory_get_item(ifactory,
-                                                    "/Message/Reply to");
+                                                    "/View/Reply to");
                gtk_check_menu_item_set_active
                        (GTK_CHECK_MENU_ITEM(menuitem), TRUE);
                gtk_entry_set_text(GTK_ENTRY(reply_entry),
@@ -4466,17 +4689,19 @@ 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:");
        }
 
-       menuitem = gtk_item_factory_get_item(ifactory, "/Tool/Show ruler");
+#if 0 /* NEW COMPOSE GUI */
+       menuitem = gtk_item_factory_get_item(ifactory, "/View/Ruler");
        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),
                                       prefs_common.show_ruler);
+#endif                                
 
 #if USE_GPGME
        menuitem = gtk_item_factory_get_item(ifactory, "/Message/Sign");
        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),
-                                      prefs_common.default_sign);
+                                      account->default_sign);
        menuitem = gtk_item_factory_get_item(ifactory, "/Message/Encrypt");
        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),
-                                      prefs_common.default_encrypt);
+                                      account->default_encrypt);
 #endif /* USE_GPGME */
 
        addressbook_set_target_compose(compose);
@@ -4511,32 +4736,14 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
                gtk_widget_hide(ruler_hbox);
 
        select_account(compose, account);
+       set_toolbar_style(compose);
 
        return compose;
 }
 
-#include "pixmaps/stock_mail_send.xpm"
-#include "pixmaps/stock_mail_send_queue.xpm"
-#include "pixmaps/stock_mail.xpm"
-#include "pixmaps/stock_paste.xpm"
-#include "pixmaps/stock_mail_attach.xpm"
-#include "pixmaps/stock_mail_compose.xpm"
-#include "pixmaps/linewrap.xpm"
-#include "pixmaps/tb_address_book.xpm"
-
-#define CREATE_TOOLBAR_ICON(xpm_d) \
-{ \
-       icon = gdk_pixmap_create_from_xpm_d(container->window, &mask, \
-                                           &container->style->white, \
-                                           xpm_d); \
-       icon_wid = gtk_pixmap_new(icon, mask); \
-}
-
 static void compose_toolbar_create(Compose *compose, GtkWidget *container)
 {
        GtkWidget *toolbar;
-       GdkPixmap *icon;
-       GdkBitmap *mask;
        GtkWidget *icon_wid;
        GtkWidget *send_btn;
        GtkWidget *sendl_btn;
@@ -4556,15 +4763,14 @@ static void compose_toolbar_create(Compose *compose, GtkWidget *container)
        gtk_toolbar_set_space_style(GTK_TOOLBAR(toolbar),
                                    GTK_TOOLBAR_SPACE_LINE);
 
-       CREATE_TOOLBAR_ICON(stock_mail_send_xpm);
+       icon_wid = stock_pixmap_widget(container, STOCK_PIXMAP_MAIL_SEND);
        send_btn = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
                                           _("Send"),
                                           _("Send message"),
                                           "Send",
                                           icon_wid, toolbar_send_cb, compose);
 
-       CREATE_TOOLBAR_ICON(stock_mail_send_queue_xpm);
-       /* CREATE_TOOLBAR_ICON(tb_mail_queue_send_xpm); */
+       icon_wid = stock_pixmap_widget(container, STOCK_PIXMAP_MAIL_SEND_QUEUE);
        sendl_btn = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
                                           _("Send later"),
                                           _("Put into queue folder and send later"),
@@ -4572,7 +4778,7 @@ static void compose_toolbar_create(Compose *compose, GtkWidget *container)
                                           icon_wid, toolbar_send_later_cb,
                                           compose);
 
-       CREATE_TOOLBAR_ICON(stock_mail_xpm);
+       icon_wid = stock_pixmap_widget(container, STOCK_PIXMAP_MAIL);
        draft_btn = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
                                            _("Draft"),
                                            _("Save to draft folder"),
@@ -4582,7 +4788,7 @@ static void compose_toolbar_create(Compose *compose, GtkWidget *container)
 
        gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
 
-       CREATE_TOOLBAR_ICON(stock_paste_xpm);
+       icon_wid = stock_pixmap_widget(container, STOCK_PIXMAP_INSERT_FILE);
        insert_btn = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
                                             _("Insert"),
                                             _("Insert file"),
@@ -4590,7 +4796,7 @@ static void compose_toolbar_create(Compose *compose, GtkWidget *container)
                                             icon_wid, toolbar_insert_cb,
                                             compose);
 
-       CREATE_TOOLBAR_ICON(stock_mail_attach_xpm);
+       icon_wid = stock_pixmap_widget(container, STOCK_PIXMAP_MAIL_ATTACH);
        attach_btn = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
                                             _("Attach"),
                                             _("Attach file"),
@@ -4600,7 +4806,7 @@ static void compose_toolbar_create(Compose *compose, GtkWidget *container)
 
        gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
 
-       CREATE_TOOLBAR_ICON(stock_mail_xpm);
+       icon_wid = stock_pixmap_widget(container, STOCK_PIXMAP_MAIL_SIGN);
        sig_btn = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
                                          _("Signature"),
                                          _("Insert signature"),
@@ -4609,7 +4815,7 @@ static void compose_toolbar_create(Compose *compose, GtkWidget *container)
 
        gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
 
-       CREATE_TOOLBAR_ICON(stock_mail_compose_xpm);
+       icon_wid = stock_pixmap_widget(container, STOCK_PIXMAP_EDIT_EXTERN);
        exteditor_btn = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
                                                _("Editor"),
                                                _("Edit with external editor"),
@@ -4618,10 +4824,10 @@ static void compose_toolbar_create(Compose *compose, GtkWidget *container)
                                                toolbar_ext_editor_cb,
                                                compose);
 
-       CREATE_TOOLBAR_ICON(linewrap_xpm);
+       icon_wid = stock_pixmap_widget(container, STOCK_PIXMAP_LINEWRAP);
        linewrap_btn = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
                                               _("Linewrap"),
-                                              _("Wrap current paragraph"),
+                                              _("Wrap all long lines"),
                                               "Linewrap",
                                               icon_wid,
                                               toolbar_linewrap_cb,
@@ -4629,7 +4835,7 @@ static void compose_toolbar_create(Compose *compose, GtkWidget *container)
 
        gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
 
-       CREATE_TOOLBAR_ICON(tb_address_book_xpm);
+       icon_wid = stock_pixmap_widget(container, STOCK_PIXMAP_ADDRESS_BOOK);
        addrbook_btn = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
                                               _("Address"),
                                               _("Address book"),
@@ -4651,8 +4857,6 @@ static void compose_toolbar_create(Compose *compose, GtkWidget *container)
        gtk_widget_show_all(toolbar);
 }
 
-#undef CREATE_TOOLBAR_ICON
-
 static GtkWidget *compose_account_option_menu_create(Compose *compose)
 {
        GList *accounts;
@@ -4728,7 +4932,22 @@ void compose_reflect_prefs_all(void)
        }
 }
 
-static void compose_template_apply(Compose *compose, Template *tmpl)
+void compose_reflect_prefs_pixmap_theme(void)
+{
+       GList *cur;
+       Compose *compose;
+
+       for (cur = compose_list; cur != NULL; cur = cur->next) {
+               compose = (Compose *)cur->data;
+               gtk_container_remove(GTK_CONTAINER(compose->handlebox), GTK_WIDGET(compose->toolbar));
+               compose->toolbar = NULL;
+               compose_toolbar_create(compose, compose->handlebox);
+               set_toolbar_style(compose);
+       }
+}
+
+static void compose_template_apply(Compose *compose, Template *tmpl,
+                                  gboolean replace)
 {
        gchar *qmark;
        gchar *parsed_str;
@@ -4736,19 +4955,22 @@ static void compose_template_apply(Compose *compose, Template *tmpl)
        if (!tmpl || !tmpl->value) return;
 
        gtk_stext_freeze(GTK_STEXT(compose->text));
-        
+
        if (tmpl->subject && *tmpl->subject != '\0')
                gtk_entry_set_text(GTK_ENTRY(compose->subject_entry),
                                   tmpl->subject);
        if (tmpl->to && *tmpl->to != '\0')
                compose_entry_append(compose, tmpl->to, COMPOSE_TO);
 
+       if (replace)
+               gtk_stext_clear(GTK_STEXT(compose->text));
+
        if (compose->replyinfo == NULL) {
                MsgInfo dummyinfo;
 
                memset(&dummyinfo, 0, sizeof(MsgInfo));
                parsed_str = compose_quote_fmt(compose, &dummyinfo,
-                                              tmpl->value, NULL);
+                                              tmpl->value, NULL, NULL);
        } else {
                if (prefs_common.quotemark && *prefs_common.quotemark)
                        qmark = prefs_common.quotemark;
@@ -4756,12 +4978,20 @@ static void compose_template_apply(Compose *compose, Template *tmpl)
                        qmark = "> ";
 
                parsed_str = compose_quote_fmt(compose, compose->replyinfo,
-                                              tmpl->value, qmark);
+                                              tmpl->value, qmark, NULL);
        }
 
-       if (parsed_str && prefs_common.auto_sig)
+       if (replace && parsed_str && prefs_common.auto_sig)
                compose_insert_sig(compose);
 
+       if (replace && parsed_str) {
+               gtk_editable_set_position(GTK_EDITABLE(compose->text), 0);
+               gtk_stext_set_point(GTK_STEXT(compose->text), 0);
+       }
+
+       if (parsed_str)
+               compose_changed_cb(NULL, compose);
+
        gtk_stext_thaw(GTK_STEXT(compose->text));
 }
 
@@ -4808,6 +5038,12 @@ static void compose_destroy(Compose *compose)
        if (addressbook_get_target_compose() == compose)
                addressbook_set_target_compose(NULL);
 
+#if USE_PSPELL
+        if (compose->gtkpspell) {
+               gtkpspell_delete(compose->gtkpspell);
+        }
+#endif
+
        prefs_common.compose_width = compose->scrolledwin->allocation.width;
        prefs_common.compose_height = compose->window->allocation.height;
 
@@ -4893,7 +5129,7 @@ static void compose_attach_property(Compose *compose)
                GtkWidget *menuitem;
 
                cancelled = FALSE;
-                gtk_main();
+               gtk_main();
 
                if (cancelled == TRUE) {
                        gtk_widget_hide(attach_prop.window);
@@ -5051,13 +5287,19 @@ static void compose_attach_property_create(gboolean *cancelled)
                         GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
 
        optmenu = gtk_option_menu_new();
-       gtk_box_pack_start(GTK_BOX(hbox), optmenu, FALSE, FALSE, 0);
+       gtk_box_pack_start(GTK_BOX(hbox), optmenu, TRUE, TRUE, 0);
 
        optmenu_menu = gtk_menu_new();
        MENUITEM_ADD(optmenu_menu, menuitem, "7bit", ENC_7BIT);
+       gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), optmenu_menu);
+#if 0
        gtk_widget_set_sensitive(menuitem, FALSE);
+#endif
        MENUITEM_ADD(optmenu_menu, menuitem, "8bit", ENC_8BIT);
+       gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), optmenu_menu);
+#if 0
        gtk_widget_set_sensitive(menuitem, FALSE);
+#endif
        MENUITEM_ADD(optmenu_menu, menuitem, "quoted-printable", ENC_QUOTED_PRINTABLE);
        gtk_widget_set_sensitive(menuitem, FALSE);
        MENUITEM_ADD(optmenu_menu, menuitem, "base64", ENC_BASE64);
@@ -5217,7 +5459,7 @@ static gint compose_exec_ext_editor_real(const gchar *file)
                g_snprintf(buf, sizeof(buf), def_cmd, file);
        }
 
-       cmdline = g_strsplit(buf, " ", 1024);
+       cmdline = strsplit_with_quote(buf, " ", 1024);
        execvp(cmdline[0], cmdline);
 
        perror("execvp");
@@ -5357,6 +5599,73 @@ static void compose_set_ext_editor_sensitive(Compose *compose,
        gtk_widget_set_sensitive(compose->linewrap_btn,  sensitive);
 }
 
+/**
+ * compose_undo_state_changed:
+ *
+ * Change the sensivity of the menuentries undo and redo
+ **/
+static void compose_undo_state_changed(UndoMain *undostruct, gint undo_state,
+                                      gint redo_state, gpointer data)
+{
+       GtkWidget *widget = GTK_WIDGET(data);
+       GtkItemFactory *ifactory;
+
+       g_return_if_fail(widget != NULL);
+
+       debug_print("Set_undo.  UNDO:%i  REDO:%i\n", undo_state, redo_state);
+
+       ifactory = gtk_item_factory_from_widget(widget);
+
+       switch (undo_state) {
+       case UNDO_STATE_TRUE:
+               if (!undostruct->undo_state) {
+                       debug_print ("Set_undo - Testpoint\n");
+                       undostruct->undo_state = TRUE;
+                       menu_set_sensitive(ifactory, "/Edit/Undo", TRUE);
+               }
+               break;
+       case UNDO_STATE_FALSE:
+               if (undostruct->undo_state) {
+                       undostruct->undo_state = FALSE;
+                       menu_set_sensitive(ifactory, "/Edit/Undo", FALSE);
+               }
+               break;
+       case UNDO_STATE_UNCHANGED:
+               break;
+       case UNDO_STATE_REFRESH:
+               menu_set_sensitive(ifactory, "/Edit/Undo",
+                                  undostruct->undo_state);
+               break;
+       default:
+               g_warning("Undo state not recognized");
+               break;
+       }
+
+       switch (redo_state) {
+       case UNDO_STATE_TRUE:
+               if (!undostruct->redo_state) {
+                       undostruct->redo_state = TRUE;
+                       menu_set_sensitive(ifactory, "/Edit/Redo", TRUE);
+               }
+               break;
+       case UNDO_STATE_FALSE:
+               if (undostruct->redo_state) {
+                       undostruct->redo_state = FALSE;
+                       menu_set_sensitive(ifactory, "/Edit/Redo", FALSE);
+               }
+               break;
+       case UNDO_STATE_UNCHANGED:
+               break;
+       case UNDO_STATE_REFRESH:
+               menu_set_sensitive(ifactory, "/Edit/Redo",
+                                  undostruct->redo_state);
+               break;
+       default:
+               g_warning("Redo state not recognized");
+               break;
+       }
+}
+
 static gint calc_cursor_xpos(GtkSText *text, gint extra, gint char_width)
 {
        gint cursor_pos;
@@ -5451,6 +5760,10 @@ static void toolbar_address_cb(GtkWidget *widget, gpointer data)
 
 static void select_account(Compose * compose, PrefsAccount * ac)
 {
+#if USE_GPGME
+       GtkItemFactory *ifactory;
+       GtkWidget *menuitem;
+#endif /* USE_GPGME */
        compose->account = ac;
        compose_set_title(compose);
 
@@ -5525,6 +5838,30 @@ static void select_account(Compose * compose, PrefsAccount * ac)
                }
                gtk_widget_queue_resize(compose->table_vbox);
 #endif
+#if USE_GPGME
+               ifactory = gtk_item_factory_from_widget(compose->menubar);
+                       menu_set_sensitive(ifactory,
+                                          "/Message/Sign", TRUE);
+                       menu_set_sensitive(ifactory,
+                                          "/Message/Encrypt", TRUE);
+
+                       menuitem = gtk_item_factory_get_item(ifactory, "/Message/Sign");
+               if (ac->default_sign)
+                       gtk_check_menu_item_set_active
+                               (GTK_CHECK_MENU_ITEM(menuitem), TRUE);
+               else
+                       gtk_check_menu_item_set_active
+                               (GTK_CHECK_MENU_ITEM(menuitem), FALSE);
+
+                       menuitem = gtk_item_factory_get_item(ifactory, "/Message/Encrypt");
+               if (ac->default_encrypt)
+                       gtk_check_menu_item_set_active
+                               (GTK_CHECK_MENU_ITEM(menuitem), TRUE);
+               else
+                       gtk_check_menu_item_set_active
+                               (GTK_CHECK_MENU_ITEM(menuitem), FALSE);
+#endif /* USE_GPGME */
+
 }
 
 static void account_activated(GtkMenuItem *menuitem, gpointer data)
@@ -5592,8 +5929,15 @@ static void compose_send_cb(gpointer data, guint action, GtkWidget *widget)
 {
        Compose *compose = (Compose *)data;
        gint val;
+       
+       if (prefs_common.work_offline)
+               if (alertpanel(_("Offline warning"), 
+                              _("You're working offline. Override?"),
+                              _("Yes"), _("No"), NULL) != G_ALERTDEFAULT)
+               return;
 
        val = compose_send(compose);
+
        if (val == 0) gtk_widget_destroy(compose->window);
 }
 
@@ -5603,7 +5947,7 @@ static void compose_send_later_cb(gpointer data, guint action,
        Compose *compose = (Compose *)data;
        gint val;
 
-       val = compose_queue(compose, NULL, NULL);
+       val = compose_queue_sub(compose, NULL, NULL, TRUE);
        if (!val) gtk_widget_destroy(compose->window);
 }
 
@@ -5612,24 +5956,35 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
        Compose *compose = (Compose *)data;
        FolderItem *draft;
        gchar *tmp;
+       gint msgnum;
+       MsgFlags flag = {0, 0};
+       static gboolean lock = FALSE;
 
-       draft = folder_get_default_draft();
+       if (lock) return;
 
-        tmp = g_strdup_printf("%s%cdraft.%d", g_get_tmp_dir(),
+       draft = account_get_special_folder(compose->account, F_DRAFT);
+       g_return_if_fail(draft != NULL);
+
+       lock = TRUE;
+
+       tmp = g_strdup_printf("%s%cdraft.%d", g_get_tmp_dir(),
                              G_DIR_SEPARATOR, (gint)compose);
 
        if (compose_write_to_file(compose, tmp, TRUE) < 0) {
                g_free(tmp);
+               lock = FALSE;
                return;
        }
 
        folder_item_scan(draft);
-       if (folder_item_add_msg(draft, tmp, TRUE) < 0) {
+       if ((msgnum = folder_item_add_msg(draft, tmp, TRUE)) < 0) {
                unlink(tmp);
                g_free(tmp);
+               lock = FALSE;
                return;
        }
        g_free(tmp);
+       draft->mtime = 0;       /* force updating */
 
        if (compose->mode == COMPOSE_REEDIT) {
                compose_remove_reedit_target(compose);
@@ -5639,10 +5994,37 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                                               TRUE);
        }
 
+       procmsg_add_flags(draft, msgnum, flag);
        folder_item_scan(draft);
        folderview_update_item(draft, TRUE);
 
-       gtk_widget_destroy(compose->window);
+       lock = FALSE;
+
+       /* 0: quit editing  1: keep editing */
+       if (action == 0)
+               gtk_widget_destroy(compose->window);
+       else {
+               struct stat s;
+               gchar *path;
+
+               path = folder_item_fetch_msg(draft, msgnum);
+               g_return_if_fail(path != NULL);
+               if (stat(path, &s) < 0) {
+                       FILE_OP_ERROR(path, "stat");
+                       g_free(path);
+                       lock = FALSE;
+                       return;
+               }
+               g_free(path);
+
+               procmsg_msginfo_free(compose->targetinfo);
+               compose->targetinfo = g_new0(MsgInfo, 1);
+               compose->targetinfo->msgnum = msgnum;
+               compose->targetinfo->size = s.st_size;
+               compose->targetinfo->mtime = s.st_mtime;
+               compose->targetinfo->folder = draft;
+               compose->mode = COMPOSE_REEDIT;
+       }
 }
 
 static void compose_attach_cb(gpointer data, guint action, GtkWidget *widget)
@@ -5660,7 +6042,8 @@ static void compose_attach_cb(gpointer data, guint action, GtkWidget *widget)
 
                for ( tmp = file_list; tmp; tmp = tmp->next) {
                        gchar *file = (gchar *) tmp->data;
-                       compose_attach_append(compose, file, MIME_UNKNOWN);
+                       compose_attach_append(compose, file, file, NULL);
+                       compose_changed_cb(NULL, compose);
                        g_free(file);
                }
                g_list_free(file_list);
@@ -5719,12 +6102,6 @@ static void compose_close_cb(gpointer data, guint action, GtkWidget *widget)
                        return;
                }
        }
-#if USE_PSPELL
-        if (compose->gtkpspell) {
-               gtkpspell_detach(compose->gtkpspell);
-               compose->gtkpspell = gtkpspell_delete(compose->gtkpspell);
-        }
-#endif
        gtk_widget_destroy(compose->window);
 }
 
@@ -5739,11 +6116,22 @@ static void compose_template_activate_cb(GtkWidget *widget, gpointer data)
 {
        Compose *compose = (Compose *)data;
        Template *tmpl;
+       gchar *msg;
+       AlertValue val;
 
        tmpl = gtk_object_get_data(GTK_OBJECT(widget), "template");
        g_return_if_fail(tmpl != NULL);
 
-       compose_template_apply(compose, tmpl);
+       msg = g_strdup_printf(_("Do you want to apply the template `%s' ?"),
+                             tmpl->name);
+       val = alertpanel(_("Apply template"), msg,
+                        _("Replace"), _("Insert"), _("Cancel"));
+       g_free(msg);
+
+       if (val == G_ALERTDEFAULT)
+               compose_template_apply(compose, tmpl, TRUE);
+       else if (val == G_ALERTALTERNATE)
+               compose_template_apply(compose, tmpl, FALSE);
 }
 
 static void compose_ext_editor_cb(gpointer data, guint action,
@@ -5759,12 +6147,12 @@ static void compose_destroy_cb(GtkWidget *widget, Compose *compose)
        compose_destroy(compose);
 }
 
-static void compose_undo_cb(Compose *compose) 
+static void compose_undo_cb(Compose *compose)
 {
        undo_undo(compose->undostruct);
 }
 
-static void compose_redo_cb(Compose *compose) 
+static void compose_redo_cb(Compose *compose)
 {
        undo_redo(compose->undostruct);
 }
@@ -5801,6 +6189,69 @@ static void compose_allsel_cb(Compose *compose)
                        (GTK_EDITABLE(compose->focused_editable), 0, -1);
 }
 
+static void compose_move_beginning_of_line_cb(Compose *compose)
+{
+       if (compose->focused_editable &&
+               GTK_WIDGET_HAS_FOCUS(compose->focused_editable))
+               gtk_stext_move_beginning_of_line(GTK_STEXT(compose->focused_editable));
+}
+
+static void compose_gtk_stext_action_cb(Compose *compose, ComposeCallGtkSTextAction action)
+{
+       if (!(compose->focused_editable && GTK_WIDGET_HAS_FOCUS(compose->focused_editable))) return;
+               
+       switch (action) {
+               case COMPOSE_CALL_GTK_STEXT_MOVE_BEGINNING_OF_LINE:
+                       gtk_stext_move_beginning_of_line(GTK_STEXT(compose->focused_editable));
+                       break;
+               case COMPOSE_CALL_GTK_STEXT_MOVE_FORWARD_CHARACTER:
+                       gtk_stext_move_forward_character(GTK_STEXT(compose->focused_editable));
+                       break;
+               case COMPOSE_CALL_GTK_STEXT_MOVE_BACKWARD_CHARACTER:
+                       gtk_stext_move_backward_character(GTK_STEXT(compose->focused_editable));
+                       break;
+               case COMPOSE_CALL_GTK_STEXT_MOVE_FORWARD_WORD:
+                       gtk_stext_move_forward_word(GTK_STEXT(compose->focused_editable));
+                       break;
+               case COMPOSE_CALL_GTK_STEXT_MOVE_BACKWARD_WORD:
+                       gtk_stext_move_backward_word(GTK_STEXT(compose->focused_editable));
+                       break;
+               case COMPOSE_CALL_GTK_STEXT_MOVE_END_OF_LINE:
+                       gtk_stext_move_end_of_line(GTK_STEXT(compose->focused_editable));
+                       break;
+               case COMPOSE_CALL_GTK_STEXT_MOVE_NEXT_LINE:
+                       gtk_stext_move_next_line(GTK_STEXT(compose->focused_editable));
+                       break;
+               case COMPOSE_CALL_GTK_STEXT_MOVE_PREVIOUS_LINE:
+                       gtk_stext_move_previous_line(GTK_STEXT(compose->focused_editable));
+                       break;
+               case COMPOSE_CALL_GTK_STEXT_DELETE_FORWARD_CHARACTER:
+                       gtk_stext_delete_forward_character(GTK_STEXT(compose->focused_editable));
+                       break;
+               case COMPOSE_CALL_GTK_STEXT_DELETE_BACKWARD_CHARACTER:
+                       gtk_stext_delete_backward_character(GTK_STEXT(compose->focused_editable));
+                       break;
+               case COMPOSE_CALL_GTK_STEXT_DELETE_FORWARD_WORD:
+                       gtk_stext_delete_forward_word(GTK_STEXT(compose->focused_editable));
+                       break;
+               case COMPOSE_CALL_GTK_STEXT_DELETE_BACKWARD_WORD:
+                       gtk_stext_delete_backward_word(GTK_STEXT(compose->focused_editable));
+                       break;
+               case COMPOSE_CALL_GTK_STEXT_DELETE_LINE:
+                       gtk_stext_delete_line(GTK_STEXT(compose->focused_editable));
+                       break;
+               case COMPOSE_CALL_GTK_STEXT_DELETE_LINE_N:
+                       gtk_stext_delete_line(GTK_STEXT(compose->focused_editable));
+                       gtk_stext_delete_forward_character(GTK_STEXT(compose->focused_editable));
+                       break;
+               case COMPOSE_CALL_GTK_STEXT_DELETE_TO_LINE_END:
+                       gtk_stext_delete_to_line_end(GTK_STEXT(compose->focused_editable));
+                       break;
+               default:
+                       break;
+       }
+}
+
 static void compose_grab_focus_cb(GtkWidget *widget, Compose *compose)
 {
        if (GTK_IS_EDITABLE(widget))
@@ -6026,8 +6477,10 @@ static void compose_attach_drag_received_cb (GtkWidget           *widget,
 
        list = uri_list_extract_filenames((const gchar *)data->data);
        for (tmp = list; tmp != NULL; tmp = tmp->next)
-               compose_attach_append(compose, (const gchar *)tmp->data,
-                                     MIME_UNKNOWN);
+               compose_attach_append
+                       (compose, (const gchar *)tmp->data,
+                        (const gchar *)tmp->data, NULL);
+       if (list) compose_changed_cb(NULL, compose);
        list_free_strings(list);
        g_list_free(list);
 }
@@ -6145,7 +6598,16 @@ void compose_headerentry_key_press_event_cb(GtkWidget *entry,
                        g_slist_remove(headerentry->compose->header_list,
                                       headerentry);
                g_free(headerentry);
+       } else  if (event->keyval == GDK_Tab) {
+               if (headerentry->compose->header_last == headerentry) {
+                       /* Override default next focus, and give it to subject_entry
+                        * instead of notebook tabs
+                        */
+                       gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key-press-event"); 
+                       gtk_widget_grab_focus(headerentry->compose->subject_entry);
+               }
        }
+
 }
 
 void compose_headerentry_changed_cb(GtkWidget *entry,
@@ -6160,72 +6622,122 @@ void compose_headerentry_changed_cb(GtkWidget *entry,
                        (GTK_OBJECT(entry),
                         GTK_SIGNAL_FUNC(compose_headerentry_changed_cb),
                         headerentry);
+               /* Automatically scroll down */
+               compose_show_first_last_header(headerentry->compose, FALSE);
+               
        }
 }
 
-/**
- * undo_set_undo:
- *
- * Change the sensivity of the menuentries undo and redo
- **/
-static void compose_set_undo(UndoMain *undostruct, gint undo_state, 
-                            gint redo_state, GtkWidget *changewidget) 
+static void compose_show_first_last_header(Compose *compose, gboolean show_first)
+{
+       GtkAdjustment *vadj;
+
+       g_return_if_fail(compose);
+       g_return_if_fail(GTK_IS_WIDGET(compose->header_table));
+       g_return_if_fail(GTK_IS_VIEWPORT(compose->header_table->parent));
+
+       vadj = gtk_viewport_get_vadjustment(GTK_VIEWPORT(compose->header_table->parent));
+       gtk_adjustment_set_value(vadj, (show_first ? vadj->lower : vadj->upper));
+}
+
+static void text_activated(GtkWidget *widget, Compose *compose)
+{
+       compose_send_control_enter(compose);
+}
+
+static gboolean compose_send_control_enter(Compose *compose)
 {
+       GdkEvent *ev;
+       GdkEventKey *kev;
        GtkItemFactory *ifactory;
-        debug_print ("Set_undo.  UNDO:%i  REDO:%i\n",
-                 undo_state,
-                 redo_state);
+       GtkAccelEntry *accel;
+       GtkWidget *send_menu;
+       GSList *list;
+       GdkModifierType ignored_mods =
+               (GDK_LOCK_MASK | GDK_MOD2_MASK | GDK_MOD3_MASK |
+                GDK_MOD4_MASK | GDK_MOD5_MASK);
 
-       g_return_if_fail (changewidget != NULL);
+       ev = gtk_get_current_event();
+       if (ev->type != GDK_KEY_PRESS) return FALSE;
 
-       ifactory = gtk_item_factory_from_widget(changewidget);
+       kev = (GdkEventKey *)ev;
+       if (!(kev->keyval == GDK_Return && (kev->state & GDK_CONTROL_MASK)))
+               return FALSE;
 
-       /* Set undo */
-        switch (undo_state) {
-        case UNDO_STATE_TRUE:
-                if (!undostruct->undo_state) {
-                       debug_print ("Set_undo - Testpoint\n");
-                        undostruct->undo_state = TRUE;
-                       menu_set_sensitive(ifactory, "/Edit/Undo", TRUE);
-                }
-                break;
-        case UNDO_STATE_FALSE:
-                if (undostruct->undo_state) {
-                        undostruct->undo_state = FALSE;
-                       menu_set_sensitive(ifactory, "/Edit/Undo", FALSE);
-                }
-                break;
-        case UNDO_STATE_UNCHANGED:
-                break;
-        case UNDO_STATE_REFRESH:
-               menu_set_sensitive(ifactory, "/Edit/Undo", undostruct->undo_state);
-                break;
-        default:
-                g_warning ("Undo state not recognized");
-               break;
-        }
+       ifactory = gtk_item_factory_from_widget(compose->menubar);
+       send_menu = gtk_item_factory_get_widget(ifactory, "/Message/Send");
+       list = gtk_accel_group_entries_from_object(GTK_OBJECT(send_menu));
+       accel = (GtkAccelEntry *)list->data;
+       if (accel->accelerator_key == kev->keyval &&
+           (accel->accelerator_mods & ~ignored_mods) ==
+           (kev->state & ~ignored_mods)) {
+               compose_send_cb(compose, 0, NULL);
+               return TRUE;
+       }
 
-        /* Set redo*/
-        switch (redo_state) {
-        case UNDO_STATE_TRUE:
-                if (!undostruct->redo_state) {
-                        undostruct->redo_state = TRUE;
-                       menu_set_sensitive(ifactory, "/Edit/Redo", TRUE);
-                }
-                break;
-        case UNDO_STATE_FALSE:
-                if (undostruct->redo_state) {
-                        undostruct->redo_state = FALSE;
-                       menu_set_sensitive(ifactory, "/Edit/Redo", FALSE);
-                }
-                break;
-        case UNDO_STATE_UNCHANGED:
-                break;
-        case UNDO_STATE_REFRESH:
-               menu_set_sensitive(ifactory, "/Edit/Redo", undostruct->redo_state);
-                break;
-        default:
-                g_warning ("Redo state not recognized");
+       return FALSE;
+}
+
+#if USE_PSPELL
+static void compose_check_all(Compose *compose)
+{
+       if (compose->gtkpspell)
+               gtkpspell_check_all(compose->gtkpspell);
+}
+
+static void compose_highlight_all(Compose *compose)
+{
+       if (compose->gtkpspell)
+               gtkpspell_highlight_all(compose->gtkpspell);
+}
+
+static void compose_check_backwards(Compose *compose)
+{
+       if (compose->gtkpspell) 
+               gtkpspell_check_backwards(compose->gtkpspell);
+       else {
+               GtkItemFactory *ifactory;
+               ifactory = gtk_item_factory_from_widget(compose->popupmenu);
+               menu_set_sensitive(ifactory, "/Edit/Check backwards misspelled word", FALSE);
+               menu_set_sensitive(ifactory, "/Edit/Forward to next misspelled word", FALSE);
+       }
+}
+
+static void compose_check_forwards_go(Compose *compose)
+{
+       if (compose->gtkpspell) 
+               gtkpspell_check_forwards_go(compose->gtkpspell);
+       else {
+               GtkItemFactory *ifactory;
+               ifactory = gtk_item_factory_from_widget(compose->popupmenu);
+               menu_set_sensitive(ifactory, "/Edit/Check backwards misspelled word", FALSE);
+               menu_set_sensitive(ifactory, "/Edit/Forward to next misspelled word", FALSE);
+       }
+}
+#endif
+
+static void set_toolbar_style(Compose *compose)
+{
+       switch (prefs_common.toolbar_style) {
+       case TOOLBAR_NONE:
+               gtk_widget_hide(compose->handlebox);
                break;
-        }
+       case TOOLBAR_ICON:
+               gtk_toolbar_set_style(GTK_TOOLBAR(compose->toolbar),
+                                     GTK_TOOLBAR_ICONS);
+               break;
+       case TOOLBAR_TEXT:
+               gtk_toolbar_set_style(GTK_TOOLBAR(compose->toolbar),
+                                     GTK_TOOLBAR_TEXT);
+               break;
+       case TOOLBAR_BOTH:
+               gtk_toolbar_set_style(GTK_TOOLBAR(compose->toolbar),
+                                     GTK_TOOLBAR_BOTH);
+               break;
+       }
+       
+       if (prefs_common.toolbar_style != TOOLBAR_NONE) {
+               gtk_widget_show(compose->handlebox);
+               gtk_widget_queue_resize(compose->handlebox);
+       }
 }