Use selected text on reply/forward.
[claws.git] / src / compose.c
index d011e7f1541ca27329571cfe71fc349aa1e1a54e..5cd42c30eb4d9b8d968671fee4ce29f642a0285e 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 "template.h"
 #include "undo.h"
 #include "foldersel.h"
+#include "prefs_actions.h"
 
 #if USE_GPGME
 #  include "rfc2015.h"
@@ -118,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
 
@@ -152,7 +172,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    *seltext);
 
 static void compose_reply_set_entry            (Compose        *compose,
                                                 MsgInfo        *msginfo,
@@ -330,6 +351,9 @@ 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);
 
@@ -418,7 +442,8 @@ static void compose_attach_parts    (Compose        *compose,
 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 *seltext);
 
 void compose_headerentry_changed_cb       (GtkWidget          *entry,
                                            ComposeHeaderEntry *headerentry);
@@ -426,11 +451,18 @@ void compose_headerentry_key_press_event_cb(GtkWidget            *entry,
                                            GdkEventKey        *event,
                                            ComposeHeaderEntry *headerentry);
 
-gint compose_headerentry_key_press_event_tab_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 void compose_show_first_last_header(Compose *compose, gboolean show_first);
+static gboolean compose_send_control_enter (Compose *compose);
+static void text_activated                (GtkWidget   *widget,
+                                           Compose     *compose);
 
 static GtkItemFactoryEntry compose_popup_entries[] =
 {
@@ -447,30 +479,138 @@ 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},
+       {N_("/_Edit/---"),              NULL, NULL, 0, "<Separator>"},
+       {N_("/_Edit/Actio_ns"),         NULL, NULL, 0, "<Branch>"},
+#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>"},
@@ -491,9 +631,9 @@ static GtkItemFactoryEntry compose_entries[] =
        {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/_Address book"),    "<shift><control>A", compose_address_cb , 0, NULL},
        {N_("/_Tool/_Template"),        NULL, NULL, 0, "<Branch>"},
-       {N_("/_Help"),                  NULL, NULL, 0, "<LastBranch>"},
+       {N_("/_Help"),                  NULL, NULL, 0, "<Branch>"},
        {N_("/_Help/_About"),           NULL, about_show, 0, NULL}
 };
 
@@ -526,7 +666,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);
@@ -659,22 +799,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 *seltext)
 {
-       compose_generic_reply(msginfo, quote, to_all, ignore_replyto, FALSE);
+       compose_generic_reply(msginfo, quote, to_all, ignore_replyto, FALSE,
+                             seltext);
 }
 
 void compose_followup_and_reply_to(MsgInfo *msginfo, gboolean quote,
                                   gboolean to_all,
-                                  gboolean ignore_replyto)
+                                  gboolean ignore_replyto,
+                                  const gchar *seltext)
 {
-       compose_generic_reply(msginfo, quote, to_all, ignore_replyto, TRUE);
+       compose_generic_reply(msginfo, quote, to_all, ignore_replyto, TRUE,
+                             seltext);
 }
 
 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 *seltext)
 {
        Compose *compose;
        PrefsAccount *account;
@@ -781,7 +925,7 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
 
                quote_str = compose_quote_fmt(compose, msginfo,
                                              prefs_common.quotefmt,
-                                             qmark);
+                                             qmark, seltext);
        }
 
        if (prefs_common.auto_sig)
@@ -796,7 +940,7 @@ 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);
 }
 
@@ -1022,7 +1166,7 @@ if (msginfo->var && *msginfo->var) { \
 }
 
 Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
-                        gboolean as_attach)
+                        gboolean as_attach, const gchar *seltext)
 {
        Compose *compose;
        /*      PrefsAccount *account; */
@@ -1094,7 +1238,8 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
                        qmark = "> ";
 
                quote_str = compose_quote_fmt(compose, msginfo,
-                                             prefs_common.fw_quotefmt, qmark);
+                                             prefs_common.fw_quotefmt, qmark,
+                                             seltext);
                compose_attach_parts(compose, msginfo);
        }
 
@@ -1191,7 +1336,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];
@@ -1200,9 +1345,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;
@@ -1220,6 +1379,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);
 
@@ -1537,7 +1709,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 *seltext)
 {
        GtkSText *text = GTK_STEXT(compose->text);
        gchar *quote_str = NULL;
@@ -1546,7 +1719,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();
 
@@ -1558,7 +1731,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, seltext);
                quote_fmt_scan_string(fmt);
                quote_fmt_parse();
 
@@ -1571,8 +1744,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');
@@ -1609,6 +1780,12 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
                                     ? compose->mailinglist
                                     : msginfo->from ? msginfo->from : ""),
                                     COMPOSE_TO);
+
+       if (compose->replyto && to_all)
+               compose_entry_append
+                       (compose, compose->replyto, COMPOSE_CC);
+
+
        if (compose->account->protocol == A_NNTP) {
                if (ignore_replyto)
                        compose_entry_append
@@ -1708,7 +1885,7 @@ static void compose_reedit_set_entry(Compose *compose, MsgInfo *msginfo)
                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);
        }
@@ -1718,7 +1895,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);
        }
@@ -1777,12 +1954,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;
        }
@@ -1796,13 +1972,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);
 }
 
@@ -1831,8 +2003,7 @@ static void compose_insert_file(Compose *compose, const gchar *file)
                        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);
@@ -1934,7 +2105,7 @@ static void compose_attach_append(Compose *compose, const gchar *file,
 
                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);
        }
@@ -1963,7 +2134,7 @@ static void compose_attach_append(Compose *compose, const gchar *file,
 #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;                                                     \
@@ -1982,7 +2153,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);
@@ -2201,7 +2371,7 @@ static void compose_wrap_line_all(Compose *compose)
        gint ch_len;
        gboolean is_new_line = TRUE, do_delete = FALSE;
        guint qlen = 0, i_len = 0;
-       guint linewrap_quote = prefs_common.linewrap_quote;
+       gboolean linewrap_quote = TRUE;
        guint linewrap_len = prefs_common.linewrap_len;
        gchar *qfmt = prefs_common.quotemark;
        gchar cbuf[MB_LEN_MAX];
@@ -2217,7 +2387,7 @@ static void compose_wrap_line_all(Compose *compose)
                /* mark position of new line - needed for quotation wrap */
                if (is_new_line) {
                        if (linewrap_quote) {
-                               qlen = gtkut_text_str_compare
+                               qlen = gtkut_stext_str_compare
                                        (text, cur_pos, tlen, qfmt);
                                if (qlen)
                                        i_len = get_indent_length
@@ -2266,7 +2436,7 @@ static void compose_wrap_line_all(Compose *compose)
                        /* 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
+                               ilen =  gtkut_stext_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);
@@ -2282,6 +2452,11 @@ static void compose_wrap_line_all(Compose *compose)
                                        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);
@@ -2296,16 +2471,16 @@ 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
+                                       ilen =  gtkut_stext_str_compare_n
                                                (text, cur_pos, p_pos, i_len,
                                                 tlen);
                                        if (ilen) {
-                                               gtk_stext_forward_delete(text,
-                                                                        ilen);
+                                               gtk_stext_forward_delete
+                                                       (text, ilen);
                                                tlen -= ilen;
                                        }
                                } else if (qlen) {
-                                       if (gtkut_text_str_compare
+                                       if (gtkut_stext_str_compare
                                            (text, cur_pos, tlen, qfmt)) {
                                                gtk_stext_forward_delete
                                                        (text, qlen);
@@ -2320,7 +2495,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++;
                                }
 
@@ -2368,8 +2543,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
@@ -2381,7 +2556,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);
@@ -2395,7 +2570,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);
@@ -2425,7 +2600,7 @@ static void compose_wrap_line_all(Compose *compose)
                        /* should we insert quotation ? */
                        if (linewrap_quote && qlen) {
                                /* 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;
 
@@ -2456,6 +2631,7 @@ static void compose_wrap_line_all(Compose *compose)
 
        gtk_stext_thaw(text);
 }
+
 #undef GET_CHAR
 
 static void compose_set_title(Compose *compose)
@@ -2845,6 +3021,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)
 {
@@ -2960,13 +3176,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;
                }
@@ -3736,7 +3956,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,
@@ -3812,10 +4031,10 @@ 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));
 
-        gtk_signal_connect(GTK_OBJECT(entry), "key-press-event", GTK_SIGNAL_FUNC(compose_headerentry_key_press_event_tab_cb), headerentry);
         headerentry->compose = compose;
         headerentry->combo = combo;
         headerentry->entry = entry;
@@ -4212,6 +4431,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
 
        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);
@@ -4248,7 +4468,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) {      
@@ -4262,6 +4482,8 @@ 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),
                                 edit_vbox);
@@ -4280,19 +4502,6 @@ 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 */
@@ -4306,7 +4515,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;
 
@@ -4359,6 +4568,17 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
 
        tmpl_menu = gtk_item_factory_get_item(ifactory, "/Tool/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);
@@ -4370,11 +4590,12 @@ 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
 
+       update_compose_actions_menu(ifactory, "/Edit/Actions", compose);
+
        switch (prefs_common.toolbar_style) {
        case TOOLBAR_NONE:
                gtk_widget_hide(handlebox);
@@ -4457,6 +4678,35 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
 
        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);
 
@@ -4472,11 +4722,11 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
 
 #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);
@@ -4487,7 +4737,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
@@ -4495,8 +4745,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)
@@ -4509,7 +4758,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),
@@ -4523,17 +4772,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);
@@ -4572,23 +4823,6 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        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;
@@ -4788,19 +5022,21 @@ 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);
 
+       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;
@@ -4808,7 +5044,7 @@ 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)
@@ -4860,6 +5096,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;
 
@@ -4945,7 +5187,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);
@@ -5269,7 +5511,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");
@@ -5713,6 +5955,7 @@ static void compose_send_cb(gpointer data, guint action, GtkWidget *widget)
        gint val;
 
        val = compose_send(compose);
+
        if (val == 0) gtk_widget_destroy(compose->window);
 }
 
@@ -5731,24 +5974,34 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
        Compose *compose = (Compose *)data;
        FolderItem *draft;
        gchar *tmp;
+       gint msgnum;
+       static gboolean lock = FALSE;
+
+       if (lock) return;
 
        draft = folder_get_default_draft();
+       g_return_if_fail(draft != NULL);
+
+       lock = TRUE;
 
-        tmp = g_strdup_printf("%s%cdraft.%d", g_get_tmp_dir(),
+       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);
@@ -5761,7 +6014,33 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
        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)
@@ -5838,12 +6117,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);
 }
 
@@ -5920,6 +6193,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))
@@ -6264,7 +6600,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,
@@ -6285,23 +6630,6 @@ void compose_headerentry_changed_cb(GtkWidget *entry,
        }
 }
 
-gint compose_headerentry_key_press_event_tab_cb(GtkWidget         *entry,
-                                               GdkEventKey        *event,
-                                               ComposeHeaderEntry *headerentry)
-{
-       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);
-                       return TRUE;
-               }
-       }
-       return FALSE;
-}
-
 static void compose_show_first_last_header(Compose *compose, gboolean show_first)
 {
        GtkAdjustment *vadj;
@@ -6313,3 +6641,75 @@ static void compose_show_first_last_header(Compose *compose, gboolean show_first
        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;
+       GtkAccelEntry *accel;
+       GtkWidget *send_menu;
+       GSList *list;
+
+       ev = gtk_get_current_event();
+       if (ev->type != GDK_KEY_PRESS) return FALSE;
+
+       kev = (GdkEventKey *)ev;
+       if (!(kev->keyval == GDK_Return && (kev->state & GDK_CONTROL_MASK)))
+               return FALSE;
+
+       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 == kev->state) {
+               compose_send_cb(compose, 0, NULL);
+               return TRUE;
+       }
+
+       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