Revert previous commit (not been using commitHelper).
authorTristan Chabredier <wwp@claws-mail.org>
Fri, 6 Mar 2009 11:32:45 +0000 (11:32 +0000)
committerTristan Chabredier <wwp@claws-mail.org>
Fri, 6 Mar 2009 11:32:45 +0000 (11:32 +0000)
src/compose.c
src/folder_item_prefs.c
src/folder_item_prefs.h
src/prefs_folder_item.c

index 44280c9..4715174 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2005 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2009 Hiroyuki Yamamoto and the Claws Mail team
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -13,8 +13,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
  */
 
 #ifdef HAVE_CONFIG_H
 
 #include "defs.h"
 
+#ifndef PANGO_ENABLE_ENGINE
+#  define PANGO_ENABLE_ENGINE
+#endif
+
 #include <glib.h>
+#include <glib/gi18n.h>
 #include <gdk/gdkkeysyms.h>
-#include <gtk/gtkmain.h>
-#include <gtk/gtkmenu.h>
-#include <gtk/gtkmenuitem.h>
-#include <gtk/gtkitemfactory.h>
-#include <gtk/gtkcheckmenuitem.h>
-#include <gtk/gtkoptionmenu.h>
-#include <gtk/gtkwidget.h>
-#include <gtk/gtkclist.h>
-#include <gtk/gtkctree.h>
-#include <gtk/gtkvpaned.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtkeditable.h>
-#include <gtk/gtkwindow.h>
-#include <gtk/gtksignal.h>
-#include <gtk/gtkvbox.h>
-#include <gtk/gtkcontainer.h>
-#include <gtk/gtkhandlebox.h>
-#include <gtk/gtktoolbar.h>
-#include <gtk/gtktable.h>
-#include <gtk/gtkhbox.h>
-#include <gtk/gtklabel.h>
-#include <gtk/gtkscrolledwindow.h>
-#include <gtk/gtkthemes.h>
-#include <gtk/gtkdnd.h>
+#include <gtk/gtk.h>
+
+#include <pango/pango-break.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <time.h>
-/* #include <sys/utsname.h> */
 #include <stdlib.h>
-#include <sys/wait.h>
+#if HAVE_SYS_WAIT_H
+#  include <sys/wait.h>
+#endif
 #include <signal.h>
 #include <errno.h>
+#ifndef G_OS_WIN32  /* fixme we should have a configure test. */
 #include <libgen.h>
+#endif
 
 #if (HAVE_WCTYPE_H && HAVE_WCHAR_H)
 #  include <wchar.h>
 #  include <wctype.h>
 #endif
 
-#include "intl.h"
+#include "claws.h"
 #include "main.h"
 #include "mainwindow.h"
 #include "compose.h"
-#include "gtkstext.h"
 #include "addressbook.h"
 #include "folderview.h"
 #include "procmsg.h"
 #include "folder.h"
 #include "addr_compl.h"
 #include "quote_fmt.h"
-#include "template.h"
 #include "undo.h"
 #include "foldersel.h"
 #include "toolbar.h"
+#include "inc.h"
+#include "message_search.h"
+#include "combobox.h"
+#include "hooks.h"
+#include "privacy.h"
+#include "timing.h"
+#include "autofaces.h"
+#include "spell_entry.h"
 
-typedef enum
+enum
 {
        COL_MIMETYPE = 0,
        COL_SIZE     = 1,
-       COL_NAME     = 2
-} AttachColumnPos;
+       COL_NAME     = 2,
+       COL_DATA     = 3,
+       COL_AUTODATA = 4,
+       N_COL_COLUMNS
+};
 
-#define N_ATTACH_COLS          3
+#define N_ATTACH_COLS  (N_COL_COLUMNS)
 
 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;
+       COMPOSE_CALL_ADVANCED_ACTION_MOVE_BEGINNING_OF_LINE,
+       COMPOSE_CALL_ADVANCED_ACTION_MOVE_FORWARD_CHARACTER,
+       COMPOSE_CALL_ADVANCED_ACTION_MOVE_BACKWARD_CHARACTER,
+       COMPOSE_CALL_ADVANCED_ACTION_MOVE_FORWARD_WORD,
+       COMPOSE_CALL_ADVANCED_ACTION_MOVE_BACKWARD_WORD,
+       COMPOSE_CALL_ADVANCED_ACTION_MOVE_END_OF_LINE,
+       COMPOSE_CALL_ADVANCED_ACTION_MOVE_NEXT_LINE,
+       COMPOSE_CALL_ADVANCED_ACTION_MOVE_PREVIOUS_LINE,
+       COMPOSE_CALL_ADVANCED_ACTION_DELETE_FORWARD_CHARACTER,
+       COMPOSE_CALL_ADVANCED_ACTION_DELETE_BACKWARD_CHARACTER,
+       COMPOSE_CALL_ADVANCED_ACTION_DELETE_FORWARD_WORD,
+       COMPOSE_CALL_ADVANCED_ACTION_DELETE_BACKWARD_WORD,
+       COMPOSE_CALL_ADVANCED_ACTION_DELETE_LINE,
+       COMPOSE_CALL_ADVANCED_ACTION_DELETE_TO_LINE_END
+} ComposeCallAdvancedAction;
 
 typedef enum
 {
@@ -154,40 +149,61 @@ typedef enum
        COMPOSE_INSERT_NO_FILE
 } ComposeInsertResult;
 
-typedef enum
-{
-       COMPOSE_QUIT_EDITING,
-       COMPOSE_KEEP_EDITING,
-       COMPOSE_AUTO_SAVE
-} ComposeDraftAction;
-
 typedef enum
 {
        COMPOSE_WRITE_FOR_SEND,
        COMPOSE_WRITE_FOR_STORE
 } ComposeWriteType;
 
+typedef enum
+{
+       COMPOSE_QUOTE_FORCED,
+       COMPOSE_QUOTE_CHECK,
+       COMPOSE_QUOTE_SKIP
+} ComposeQuoteMode;
 
 #define B64_LINE_SIZE          57
 #define B64_BUFFSIZE           77
 
 #define MAX_REFERENCES_LEN     999
 
-static GdkColor quote_color = {0, 0, 0, 0xbfff};
-
 static GList *compose_list = NULL;
 
-Compose *compose_generic_new                   (PrefsAccount   *account,
+static Compose *compose_generic_new                    (PrefsAccount   *account,
                                                 const gchar    *to,
                                                 FolderItem     *item,
                                                 GPtrArray      *attach_files,
                                                 GList          *listAddress );
 
 static Compose *compose_create                 (PrefsAccount   *account,
-                                                ComposeMode     mode);
+                                                FolderItem              *item,
+                                                ComposeMode     mode,
+                                                gboolean batch);
+
+static void compose_entry_mark_default_to      (Compose          *compose,
+                                        const gchar      *address);
+static Compose *compose_followup_and_reply_to  (MsgInfo        *msginfo,
+                                        ComposeQuoteMode        quote_mode,
+                                        gboolean        to_all,
+                                        gboolean        to_sender,
+                                        const gchar    *body);
+static Compose *compose_forward_multiple       (PrefsAccount   *account, 
+                                        GSList         *msginfo_list);
+static Compose *compose_reply                  (MsgInfo        *msginfo,
+                                        ComposeQuoteMode        quote_mode,
+                                        gboolean        to_all,
+                                        gboolean        to_ml,
+                                        gboolean        to_sender,
+                                        const gchar    *body);
+static Compose *compose_reply_mode             (ComposeMode     mode, 
+                                        GSList         *msginfo_list, 
+                                        gchar          *body);
+static void compose_template_apply_fields(Compose *compose, Template *tmpl);
+static void compose_update_privacy_systems_menu(Compose        *compose);
 
 static GtkWidget *compose_account_option_menu_create
                                                (Compose        *compose);
+static void compose_set_out_encoding           (Compose        *compose);
 static void compose_set_template_menu          (Compose        *compose);
 static void compose_template_apply             (Compose        *compose,
                                                 Template       *tmpl,
@@ -195,7 +211,8 @@ static void compose_template_apply          (Compose        *compose,
 static void compose_destroy                    (Compose        *compose);
 
 static void compose_entries_set                        (Compose        *compose,
-                                                const gchar    *mailto);
+                                                const gchar    *mailto,
+                                                ComposeEntryType to_type);
 static gint compose_parse_header               (Compose        *compose,
                                                 MsgInfo        *msginfo);
 static gchar *compose_parse_references         (const gchar    *ref,
@@ -205,7 +222,10 @@ static gchar *compose_quote_fmt                    (Compose        *compose,
                                                 MsgInfo        *msginfo,
                                                 const gchar    *fmt,
                                                 const gchar    *qmark,
-                                                const gchar    *body);
+                                                const gchar    *body,
+                                                gboolean        rewrap,
+                                                gboolean        need_unescape,
+                                                const gchar *err_msg);
 
 static void compose_reply_set_entry            (Compose        *compose,
                                                 MsgInfo        *msginfo,
@@ -216,21 +236,26 @@ static void compose_reply_set_entry               (Compose        *compose,
                                                 followup_and_reply_to);
 static void compose_reedit_set_entry           (Compose        *compose,
                                                 MsgInfo        *msginfo);
+
 static void compose_insert_sig                 (Compose        *compose,
                                                 gboolean        replace);
-static gchar *compose_get_signature_str                (Compose        *compose);
 static ComposeInsertResult compose_insert_file (Compose        *compose,
                                                 const gchar    *file);
-static void compose_attach_append              (Compose        *compose,
+
+static gboolean compose_attach_append          (Compose        *compose,
                                                 const gchar    *file,
                                                 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_wrap_line_all_full         (Compose        *compose,
+
+static gboolean compose_beautify_paragraph     (Compose        *compose,
+                                                GtkTextIter    *par_iter,
+                                                gboolean        force);
+static void compose_wrap_all                   (Compose        *compose);
+static void compose_wrap_all_full              (Compose        *compose,
                                                 gboolean        autowrap);
+
 static void compose_set_title                  (Compose        *compose);
 static void compose_select_account             (Compose        *compose,
                                                 PrefsAccount   *account,
@@ -241,35 +266,39 @@ static PrefsAccount *compose_current_mail_account(void);
 static gboolean compose_check_for_valid_recipient
                                                (Compose        *compose);
 static gboolean compose_check_entries          (Compose        *compose,
-                                                gboolean       check_subject);
+                                                gboolean       check_everything);
 static gint compose_write_to_file              (Compose        *compose,
                                                 FILE           *fp,
-                                                gint            action);
+                                                gint            action,
+                                                gboolean        attach_parts);
 static gint compose_write_body_to_file         (Compose        *compose,
                                                 const gchar    *file);
-static gint compose_remove_reedit_target       (Compose        *compose);
-void compose_remove_draft                      (Compose        *compose);
-static gint compose_queue                      (Compose        *compose,
-                                                gint           *msgnum,
-                                                FolderItem     **item);
+static gint compose_remove_reedit_target       (Compose        *compose,
+                                                gboolean        force);
+static void compose_remove_draft                       (Compose        *compose);
 static gint compose_queue_sub                  (Compose        *compose,
                                                 gint           *msgnum,
                                                 FolderItem     **item,
-                                                gboolean       check_subject);
+                                                gchar          **msgpath,
+                                                gboolean       check_subject,
+                                                gboolean       remove_reedit_target);
 static void compose_add_attachments            (Compose        *compose,
                                                 MimeInfo       *parent);
 static gchar *compose_get_header               (Compose        *compose);
 
-static void compose_convert_header             (gchar          *dest,
+static void compose_convert_header             (Compose        *compose,
+                                                gchar          *dest,
                                                 gint            len,
                                                 gchar          *src,
                                                 gint            header_len,
                                                 gboolean        addr_field);
 
 static void compose_attach_info_free           (AttachInfo     *ainfo);
-static void compose_attach_remove_selected     (Compose        *compose);
+static void compose_attach_remove_selected     (GtkAction      *action,
+                                                gpointer        data);
 
-static void compose_attach_property            (Compose        *compose);
+static void compose_attach_property            (GtkAction      *action,
+                                                gpointer        data);
 static void compose_attach_property_create     (gboolean       *cancelled);
 static void attach_property_ok                 (GtkWidget      *widget,
                                                 gboolean       *cancelled);
@@ -278,32 +307,35 @@ static void attach_property_cancel                (GtkWidget      *widget,
 static gint attach_property_delete_event       (GtkWidget      *widget,
                                                 GdkEventAny    *event,
                                                 gboolean       *cancelled);
-static void attach_property_key_pressed                (GtkWidget      *widget,
+static gboolean attach_property_key_pressed    (GtkWidget      *widget,
                                                 GdkEventKey    *event,
                                                 gboolean       *cancelled);
 
-static void compose_exec_ext_editor            (Compose           *compose);
-static gint compose_exec_ext_editor_real       (const gchar       *file);
-static gboolean compose_ext_editor_kill                (Compose           *compose);
-static void compose_input_cb                   (gpointer           data,
-                                                gint               source,
-                                                GdkInputCondition  condition);
-static void compose_set_ext_editor_sensitive   (Compose           *compose,
-                                                gboolean           sensitive);
+static void compose_exec_ext_editor            (Compose        *compose);
+#ifdef G_OS_UNIX
+static gint compose_exec_ext_editor_real       (const gchar    *file);
+static gboolean compose_ext_editor_kill                (Compose        *compose);
+static gboolean compose_input_cb               (GIOChannel     *source,
+                                                GIOCondition    condition,
+                                                gpointer        data);
+static void compose_set_ext_editor_sensitive   (Compose        *compose,
+                                                gboolean        sensitive);
+#endif /* G_OS_UNIX */
 
 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);
-
 static void compose_create_header_entry        (Compose *compose);
-static void compose_add_header_entry   (Compose *compose, gchar *header, gchar *text);
-static void compose_update_priority_menu_item(Compose * compose);
+static void compose_add_header_entry   (Compose *compose, const gchar *header, gchar *text);
+static void compose_remove_header_entries(Compose *compose);
 
+static void compose_update_priority_menu_item(Compose * compose);
+#if USE_ENCHANT
+static void compose_spell_menu_changed (void *data);
+static void compose_dict_changed       (void *data);
+#endif
 static void compose_add_field_list     ( Compose *compose,
                                          GList *listAddress );
 
@@ -312,133 +344,109 @@ static void compose_add_field_list      ( Compose *compose,
 static gboolean compose_edit_size_alloc (GtkEditable   *widget,
                                         GtkAllocation  *allocation,
                                         GtkSHRuler     *shruler);
-static void account_activated          (GtkMenuItem    *menuitem,
+static void account_activated          (GtkComboBox *optmenu,
                                         gpointer        data);
-static void attach_selected            (GtkCList       *clist,
-                                        gint            row,
-                                        gint            column,
-                                        GdkEvent       *event,
-                                        gpointer        data);
-static void attach_button_pressed      (GtkWidget      *widget,
+static void attach_selected            (GtkTreeView    *tree_view, 
+                                        GtkTreePath    *tree_path,
+                                        GtkTreeViewColumn *column, 
+                                        Compose *compose);
+static gboolean attach_button_pressed  (GtkWidget      *widget,
                                         GdkEventButton *event,
                                         gpointer        data);
-static void attach_key_pressed         (GtkWidget      *widget,
+static gboolean attach_key_pressed     (GtkWidget      *widget,
                                         GdkEventKey    *event,
                                         gpointer        data);
+static void compose_send_cb            (GtkAction      *action, gpointer data);
+static void compose_send_later_cb      (GtkAction      *action, gpointer data);
+
+static void compose_save_cb            (GtkAction      *action,
+                                        gpointer        data);
+
+static void compose_attach_cb          (GtkAction      *action,
+                                        gpointer        data);
+static void compose_insert_file_cb     (GtkAction      *action,
+                                        gpointer        data);
+static void compose_insert_sig_cb      (GtkAction      *action,
+                                        gpointer        data);
+
+static void compose_close_cb           (GtkAction      *action,
+                                        gpointer        data);
+
+static void compose_set_encoding_cb    (GtkAction      *action, GtkRadioAction *current, gpointer data);
 
-static void compose_send_cb            (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-static void compose_send_later_cb      (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-
-static void compose_draft_cb           (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-
-static void compose_attach_cb          (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-static void compose_insert_file_cb     (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-static void compose_insert_sig_cb      (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-
-static void compose_close_cb           (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-
-static void compose_address_cb         (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
+static void compose_address_cb         (GtkAction      *action,
+                                        gpointer        data);
+static void about_show_cb              (GtkAction      *action,
+                                        gpointer        data);
 static void compose_template_activate_cb(GtkWidget     *widget,
                                         gpointer        data);
 
-static void compose_ext_editor_cb      (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
+static void compose_ext_editor_cb      (GtkAction      *action,
+                                        gpointer        data);
 
 static gint compose_delete_cb          (GtkWidget      *widget,
                                         GdkEventAny    *event,
                                         gpointer        data);
-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_cut_cb             (Compose        *compose);
-static void compose_copy_cb            (Compose        *compose);
-static void compose_paste_cb           (Compose        *compose);
-static void compose_paste_as_quote_cb  (Compose        *compose);
-static void compose_allsel_cb          (Compose        *compose);
+static void compose_undo_cb            (GtkAction      *action,
+                                        gpointer        data);
+static void compose_redo_cb            (GtkAction      *action,
+                                        gpointer        data);
+static void compose_cut_cb             (GtkAction      *action,
+                                        gpointer        data);
+static void compose_copy_cb            (GtkAction      *action,
+                                        gpointer        data);
+static void compose_paste_cb           (GtkAction      *action,
+                                        gpointer        data);
+static void compose_paste_as_quote_cb  (GtkAction      *action,
+                                        gpointer        data);
+static void compose_paste_no_wrap_cb   (GtkAction      *action,
+                                        gpointer        data);
+static void compose_paste_wrap_cb      (GtkAction      *action,
+                                        gpointer        data);
+static void compose_allsel_cb          (GtkAction      *action,
+                                        gpointer        data);
 
-static void compose_gtk_stext_action_cb        (Compose                   *compose,
-                                        ComposeCallGtkSTextAction  action);
+static void compose_advanced_action_cb (GtkAction      *action,
+                                        gpointer        data);
 
 static void compose_grab_focus_cb      (GtkWidget      *widget,
                                         Compose        *compose);
 
-static void compose_changed_cb         (GtkEditable    *editable,
-                                        Compose        *compose);
-static void compose_button_press_cb    (GtkWidget      *widget,
-                                        GdkEventButton *event,
+static void compose_changed_cb         (GtkTextBuffer  *textbuf,
                                         Compose        *compose);
-#if 0
-static void compose_key_press_cb       (GtkWidget      *widget,
-                                        GdkEventKey    *event,
-                                        Compose        *compose);
-#endif
 
-static void compose_toggle_autowrap_cb (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-
-#if 0
-static void compose_toggle_to_cb       (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-static void compose_toggle_cc_cb       (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-static void compose_toggle_bcc_cb      (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-static void compose_toggle_replyto_cb  (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-static void compose_toggle_followupto_cb(gpointer       data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-static void compose_toggle_attach_cb   (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-#endif
-static void compose_toggle_ruler_cb    (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-static void compose_toggle_sign_cb     (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-static void compose_toggle_encrypt_cb  (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
-static void compose_set_privacy_system_cb(GtkWidget      *widget,
-                                         gpointer        data);
-static void compose_update_privacy_system_menu_item(Compose * compose);
+static void compose_wrap_cb            (GtkAction      *action,
+                                        gpointer        data);
+static void compose_wrap_all_cb                (GtkAction      *action,
+                                        gpointer        data);
+static void compose_find_cb            (GtkAction      *action,
+                                        gpointer        data);
+static void compose_toggle_autowrap_cb (GtkToggleAction *action,
+                                        gpointer        data);
+static void compose_toggle_autoindent_cb(GtkToggleAction *action,
+                                        gpointer        data);
+
+static void compose_toggle_ruler_cb    (GtkToggleAction *action,
+                                        gpointer        data);
+static void compose_toggle_sign_cb     (GtkToggleAction *action,
+                                        gpointer        data);
+static void compose_toggle_encrypt_cb  (GtkToggleAction *action,
+                                        gpointer        data);
+static void compose_set_privacy_system_cb(GtkWidget *widget, gpointer data);
+static void compose_update_privacy_system_menu_item(Compose * compose, gboolean warn);
 static void activate_privacy_system     (Compose *compose, 
-                                         PrefsAccount *account);
+                                         PrefsAccount *account,
+                                        gboolean warn);
 static void compose_use_signing(Compose *compose, gboolean use_signing);
 static void compose_use_encryption(Compose *compose, gboolean use_encryption);
-static void compose_toggle_return_receipt_cb(gpointer data, guint action,
-                                            GtkWidget *widget);
-static void compose_toggle_remove_refs_cb(gpointer data, guint action,
-                                            GtkWidget *widget);
-static void compose_set_priority_cb    (gpointer        data,
-                                        guint           action,
-                                        GtkWidget      *widget);
+static void compose_toggle_return_receipt_cb(GtkToggleAction *action,
+                                        gpointer        data);
+static void compose_toggle_remove_refs_cb(GtkToggleAction *action,
+                                        gpointer        data);
+static void compose_set_priority_cb    (GtkAction *action, GtkRadioAction *current, gpointer data);
+static void compose_reply_change_mode  (Compose *compose, ComposeMode action);
+static void compose_reply_change_mode_cb(GtkAction *action, GtkRadioAction *current, gpointer data);
 
 static void compose_attach_drag_received_cb (GtkWidget         *widget,
                                             GdkDragContext     *drag_context,
@@ -456,224 +464,259 @@ static void compose_insert_drag_received_cb (GtkWidget          *widget,
                                             guint               info,
                                             guint               time,
                                             gpointer            user_data);
+static void compose_header_drag_received_cb (GtkWidget         *widget,
+                                            GdkDragContext     *drag_context,
+                                            gint                x,
+                                            gint                y,
+                                            GtkSelectionData   *data,
+                                            guint               info,
+                                            guint               time,
+                                            gpointer            user_data);
 
-#if 0
-static void to_activated               (GtkWidget      *widget,
-                                        Compose        *compose);
-static void newsgroups_activated       (GtkWidget      *widget,
-                                        Compose        *compose);
-static void cc_activated               (GtkWidget      *widget,
-                                        Compose        *compose);
-static void bcc_activated              (GtkWidget      *widget,
-                                        Compose        *compose);
-static void replyto_activated          (GtkWidget      *widget,
-                                        Compose        *compose);
-static void followupto_activated       (GtkWidget      *widget,
-                                        Compose        *compose);
-static void subject_activated          (GtkWidget      *widget,
-                                        Compose        *compose);
-#endif
+static gboolean compose_drag_drop          (GtkWidget *widget,
+                                            GdkDragContext *drag_context,
+                                            gint x, gint y,
+                                            guint time, gpointer user_data);
 
-static void text_activated             (GtkWidget      *widget,
-                                        Compose        *compose);
-static void text_inserted              (GtkWidget      *widget,
+static void text_inserted              (GtkTextBuffer  *buffer,
+                                        GtkTextIter    *iter,
                                         const gchar    *text,
-                                        gint            length,
-                                        gint           *position,
+                                        gint            len,
                                         Compose        *compose);
-static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
-                                 gboolean to_all, gboolean to_ml,
+static Compose *compose_generic_reply(MsgInfo *msginfo,
+                                 ComposeQuoteMode quote_mode,
+                                 gboolean to_all,
+                                 gboolean to_ml,
                                  gboolean to_sender,
                                  gboolean followup_and_reply_to,
                                  const gchar *body);
 
-void compose_headerentry_changed_cb       (GtkWidget          *entry,
+static gboolean compose_headerentry_changed_cb    (GtkWidget          *entry,
                                            ComposeHeaderEntry *headerentry);
-void compose_headerentry_key_press_event_cb(GtkWidget         *entry,
+static gboolean compose_headerentry_key_press_event_cb(GtkWidget              *entry,
                                            GdkEventKey        *event,
                                            ComposeHeaderEntry *headerentry);
-static gboolean compose_headerentry_button_pressed (GtkWidget *entry, 
-                                                   GdkEventButton *event,
-                                                   gpointer data);
 
 static void compose_show_first_last_header (Compose *compose, gboolean show_first);
 
 static void compose_allow_user_actions (Compose *compose, gboolean allow);
 
-#if USE_ASPELL
-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);
+static void compose_nothing_cb            (GtkAction *action, gpointer data)
+{
+
+}
+
+#if USE_ENCHANT
+static void compose_check_all             (GtkAction *action, gpointer data);
+static void compose_highlight_all         (GtkAction *action, gpointer data);
+static void compose_check_backwards       (GtkAction *action, gpointer data);
+static void compose_check_forwards_go     (GtkAction *action, gpointer data);
 #endif
 
-static gboolean compose_send_control_enter     (Compose        *compose);
 static gint compose_defer_auto_save_draft      (Compose        *compose);
 static PrefsAccount *compose_guess_forward_account_from_msginfo        (MsgInfo *msginfo);
 
-static void compose_close      (Compose *compose);
+static MsgInfo *compose_msginfo_new_from_compose(Compose *compose);
 
-static GtkItemFactoryEntry compose_popup_entries[] =
+#ifdef USE_ENCHANT
+static void compose_set_dictionaries_from_folder_prefs(Compose *compose,
+                                               FolderItem *folder_item);
+#endif
+static void compose_attach_update_label(Compose *compose);
+
+static void compose_attach_from_list(Compose *compose, GList *file_list, gboolean free_data);
+
+static GtkActionEntry compose_popup_entries[] =
 {
-       {N_("/_Add..."),        NULL, compose_attach_cb, 0, NULL},
-       {N_("/_Remove"),        NULL, compose_attach_remove_selected, 0, NULL},
-       {N_("/---"),            NULL, NULL, 0, "<Separator>"},
-       {N_("/_Properties..."), NULL, compose_attach_property, 0, NULL}
+       {"Compose",                     NULL, "Compose" },
+       {"Compose/Add",                 NULL, N_("_Add..."), NULL, NULL, G_CALLBACK(compose_attach_cb) },
+       {"Compose/Remove",                      NULL, N_("_Remove"), NULL, NULL, G_CALLBACK(compose_attach_remove_selected) },
+       {"Compose/---",                 NULL, "---", NULL, NULL, NULL },
+       {"Compose/Properties",          NULL, N_("_Properties..."), NULL, NULL, G_CALLBACK(compose_attach_property) },
 };
 
-static GtkItemFactoryEntry compose_entries[] =
-{
-       {N_("/_Message"),                               NULL, NULL, 0, "<Branch>"},
-       {N_("/_Message/_Send"),         "<control>Return",
-                                       compose_send_cb, 0, NULL},
-       {N_("/_Message/Send _later"),   "<shift><control>S",
-                                       compose_send_later_cb,  0, NULL},
-       {N_("/_Message/---"),                   NULL, NULL, 0, "<Separator>"},
-       {N_("/_Message/_Attach file"),          "<control>M", compose_attach_cb,      0, NULL},
-       {N_("/_Message/_Insert file"),          "<control>I", compose_insert_file_cb, 0, NULL},
-       {N_("/_Message/Insert si_gnature"),     "<control>G", compose_insert_sig_cb,  0, NULL},
-       {N_("/_Message/---"),                   NULL, NULL, 0, "<Separator>"},
-       {N_("/_Message/_Save"),
-                                               "<control>S", compose_draft_cb, COMPOSE_KEEP_EDITING, NULL},
-       {N_("/_Message/---"),                   NULL, NULL, 0, "<Separator>"},
-       {N_("/_Message/_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/Paste as _quotation"),
-                                       NULL, compose_paste_as_quote_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"),
-                                       "<control><alt>L", compose_wrap_line_all, 0, NULL},
-       {N_("/_Edit/Aut_o wrapping"),   "<shift><control>L", compose_toggle_autowrap_cb, 0, "<ToggleItem>"},
-       {N_("/_Edit/---"),              NULL, NULL, 0, "<Separator>"},
-       {N_("/_Edit/Edit with e_xternal editor"),
-                                       "<shift><control>X", compose_ext_editor_cb, 0, NULL},
-#if USE_ASPELL
-       {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>"},
+static GtkActionEntry compose_entries[] =
+{
+       {"Menu",                                NULL, "Menu" },
+/* menus */
+       {"Message",                     NULL, N_("_Message") },
+       {"Edit",                        NULL, N_("_Edit") },
+#if USE_ENCHANT
+       {"Spelling",                    NULL, N_("_Spelling") },
 #endif
-       {N_("/_Options"),               NULL, NULL, 0, "<Branch>"},
-       {N_("/_Options/Privacy System"),                NULL, NULL,   0, "<Branch>"},
-       {N_("/_Options/Privacy System/None"),   NULL, NULL,   0, "<RadioItem>"},
-       {N_("/_Options/Si_gn"),         NULL, compose_toggle_sign_cb   , 0, "<ToggleItem>"},
-       {N_("/_Options/_Encrypt"),      NULL, compose_toggle_encrypt_cb, 0, "<ToggleItem>"},
-       {N_("/_Options/---"),           NULL,           NULL,   0, "<Separator>"},
-       {N_("/_Options/_Priority"),     NULL,           NULL,   0, "<Branch>"},
-       {N_("/_Options/Priority/_Highest"), NULL, compose_set_priority_cb, PRIORITY_HIGHEST, "<RadioItem>"},
-       {N_("/_Options/Priority/Hi_gh"),    NULL, compose_set_priority_cb, PRIORITY_HIGH, "/Options/Priority/Highest"},
-       {N_("/_Options/Priority/_Normal"),  NULL, compose_set_priority_cb, PRIORITY_NORMAL, "/Options/Priority/Highest"},
-       {N_("/_Options/Priority/Lo_w"),    NULL, compose_set_priority_cb, PRIORITY_LOW, "/Options/Priority/Highest"},
-       {N_("/_Options/Priority/_Lowest"),  NULL, compose_set_priority_cb, PRIORITY_LOWEST, "/Options/Priority/Highest"},
-       {N_("/_Options/---"),           NULL,           NULL,   0, "<Separator>"},
-       {N_("/_Options/_Request Return Receipt"),       NULL, compose_toggle_return_receipt_cb, 0, "<ToggleItem>"},
-       {N_("/_Options/Remo_ve references"),    NULL, compose_toggle_remove_refs_cb, 0, "<ToggleItem>"},
-       {N_("/_Tools"),                 NULL, NULL, 0, "<Branch>"},
-       {N_("/_Tools/Show _ruler"),     NULL, compose_toggle_ruler_cb, 0, "<ToggleItem>"},
-       {N_("/_Tools/_Address book"),   "<shift><control>A", compose_address_cb , 0, NULL},
-       {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}
+       {"Options",                     NULL, N_("_Options") },
+       {"Tools",                       NULL, N_("_Tools") },
+       {"Help",                        NULL, N_("_Help") },
+/* Message menu */
+       {"Message/Send",                NULL, N_("S_end"), "<control>Return", NULL, G_CALLBACK(compose_send_cb) },
+       {"Message/SendLater",           NULL, N_("Send _later"), "<shift><control>S", NULL, G_CALLBACK(compose_send_later_cb) },
+       {"Message/---",                 NULL, "---" },
+
+       {"Message/AttachFile",          NULL, N_("_Attach file"), "<control>M", NULL, G_CALLBACK(compose_attach_cb) },
+       {"Message/InsertFile",          NULL, N_("_Insert file"), "<control>I", NULL, G_CALLBACK(compose_insert_file_cb) },
+       {"Message/InsertSig",           NULL, N_("Insert si_gnature"), "<control>G", NULL, G_CALLBACK(compose_insert_sig_cb) },
+       /* {"Message/---",              NULL, "---" }, */
+       {"Message/Save",                NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(compose_save_cb) }, /*COMPOSE_KEEP_EDITING*/
+       /* {"Message/---",              NULL, "---" }, */
+       {"Message/Close",               NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(compose_close_cb) },
+
+/* Edit menu */
+       {"Edit/Undo",                   NULL, N_("_Undo"), "<control>Z", NULL, G_CALLBACK(compose_undo_cb) },
+       {"Edit/Redo",                   NULL, N_("_Redo"), "<control>Y", NULL, G_CALLBACK(compose_redo_cb) },
+       {"Edit/---",                    NULL, "---" },
+
+       {"Edit/Cut",                    NULL, N_("Cu_t"), "<control>X", NULL, G_CALLBACK(compose_cut_cb) },
+       {"Edit/Copy",                   NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(compose_copy_cb) },
+       {"Edit/Paste",                  NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(compose_paste_cb) },
+
+       {"Edit/SpecialPaste",           NULL, N_("Special paste") },
+       {"Edit/SpecialPaste/AsQuotation",       NULL, N_("as _quotation"), NULL, NULL, G_CALLBACK(compose_paste_as_quote_cb) },
+       {"Edit/SpecialPaste/Wrapped",   NULL, N_("_wrapped"), NULL, NULL, G_CALLBACK(compose_paste_wrap_cb) },
+       {"Edit/SpecialPaste/Unwrapped", NULL, N_("_unwrapped"), NULL, NULL, G_CALLBACK(compose_paste_no_wrap_cb) },
+
+       {"Edit/SelectAll",              NULL, N_("Select _all"), "<control>A", NULL, G_CALLBACK(compose_allsel_cb) },
+
+       {"Edit/Advanced",               NULL, N_("A_dvanced") },
+       {"Edit/Advanced/BackChar",      NULL, N_("Move a character backward"), "<shift><control>B", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_BACKWARD_CHARACTER*/
+       {"Edit/Advanced/ForwChar",      NULL, N_("Move a character forward"), "<shift><control>F", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_FORWARD_CHARACTER*/
+       {"Edit/Advanced/BackWord",      NULL, N_("Move a word backward"), NULL, NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_BACKWARD_WORD*/
+       {"Edit/Advanced/ForwWord",      NULL, N_("Move a word forward"), NULL, NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_FORWARD_WORD*/
+       {"Edit/Advanced/BegLine",       NULL, N_("Move to beginning of line"), NULL, NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_BEGINNING_OF_LINE*/
+       {"Edit/Advanced/EndLine",       NULL, N_("Move to end of line"), NULL, NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_END_OF_LINE*/
+       {"Edit/Advanced/PrevLine",      NULL, N_("Move to previous line"), "<control>P", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_PREVIOUS_LINE*/
+       {"Edit/Advanced/NextLine",      NULL, N_("Move to next line"), "<control>N", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_MOVE_NEXT_LINE*/
+       {"Edit/Advanced/DelBackChar",   NULL, N_("Delete a character backward"), "<control>H", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_DELETE_BACKWARD_CHARACTER*/
+       {"Edit/Advanced/DelForwChar",   NULL, N_("Delete a character forward"), "<control>D", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_DELETE_FORWARD_CHARACTER*/
+       {"Edit/Advanced/DelBackWord",   NULL, N_("Delete a word backward"), NULL, NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_DELETE_BACKWARD_WORD*/
+       {"Edit/Advanced/DelForwWord",   NULL, N_("Delete a word forward"), NULL, NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_DELETE_FORWARD_WORD*/
+       {"Edit/Advanced/DelLine",       NULL, N_("Delete line"), "<control>U", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_DELETE_LINE*/
+       {"Edit/Advanced/DelEndLine",    NULL, N_("Delete to end of line"), "<control>K", NULL, G_CALLBACK(compose_advanced_action_cb) }, /*COMPOSE_CALL_ADVANCED_ACTION_DELETE_TO_LINE_END*/
+
+       /* {"Edit/---",                 NULL, "---" }, */
+       {"Edit/Find",           NULL, N_("_Find"), "<control>F", NULL, G_CALLBACK(compose_find_cb) },
+
+       /* {"Edit/---",                 NULL, "---" }, */
+       {"Edit/WrapPara",               NULL, N_("_Wrap current paragraph"), "<control>L", NULL, G_CALLBACK(compose_wrap_cb) }, /* 0 */
+       {"Edit/WrapAllLines",           NULL, N_("Wrap all long _lines"), "<control><alt>L", NULL, G_CALLBACK(compose_wrap_all_cb) }, /* 1 */
+       /* {"Edit/---",                 NULL, "---" }, */
+       {"Edit/ExtEditor",              NULL, N_("Edit with e_xternal editor"), "<shift><control>X", NULL, G_CALLBACK(compose_ext_editor_cb) },
+#if USE_ENCHANT
+/* Spelling menu */
+       {"Spelling/CheckAllSel",        NULL, N_("_Check all or check selection"), NULL, NULL, G_CALLBACK(compose_check_all) },
+       {"Spelling/HighlightAll",       NULL, N_("_Highlight all misspelled words"), NULL, NULL, G_CALLBACK(compose_highlight_all) },
+       {"Spelling/CheckBackwards",     NULL, N_("Check _backwards misspelled word"), NULL, NULL, G_CALLBACK(compose_check_backwards) },
+       {"Spelling/ForwardNext",        NULL, N_("_Forward to next misspelled word"), NULL, NULL, G_CALLBACK(compose_check_forwards_go) },
+
+       {"Spelling/---",                NULL, "---" },
+       {"Spelling/Options",            NULL, N_("_Options") },
+#endif
+
+/* Options menu */
+
+       {"Options/ReplyMode",           NULL, N_("Reply _mode") },
+       {"Options/---",                 NULL, "---" },
+       {"Options/PrivacySystem",       NULL, N_("Privacy _System") },
+       {"Options/PrivacySystem/PlaceHolder",   NULL, "Placeholder", NULL, NULL, G_CALLBACK(compose_nothing_cb) },
+
+       /* {"Options/---",              NULL, "---" }, */
+
+       {"Options/Priority",            NULL, N_("_Priority") },
+
+       {"Options/Encoding",            NULL, N_("Character _encoding") },
+       {"Options/Encoding/---",        NULL, "---" },
+#define ENC_ACTION(cs_char,c_char,string) \
+       { "Options/Encoding/" cs_char, NULL, N_(string), NULL, NULL, c_char }
+
+       {"Options/Encoding/Western",    NULL, N_("Western European") },
+       {"Options/Encoding/Baltic",     NULL, N_("Baltic") },
+       {"Options/Encoding/Hebrew",     NULL, N_("Hebrew") },
+       {"Options/Encoding/Arabic",     NULL, N_("Arabic") },
+       {"Options/Encoding/Cyrillic",   NULL, N_("Cyrillic") },
+       {"Options/Encoding/Japanese",   NULL, N_("Japanese") },
+       {"Options/Encoding/Chinese",    NULL, N_("Chinese") },
+       {"Options/Encoding/Korean",     NULL, N_("Korean") },
+       {"Options/Encoding/Thai",       NULL, N_("Thai") },
+
+/* Tools menu */
+       {"Tools/AddressBook",           NULL, N_("_Address book"), NULL, NULL, G_CALLBACK(compose_address_cb) }, 
+
+       {"Tools/Template",      NULL, N_("_Template") },
+       {"Tools/Template/PlaceHolder",  NULL, "Placeholder", NULL, NULL, G_CALLBACK(compose_nothing_cb) },
+       {"Tools/Actions",       NULL, N_("Actio_ns") },
+       {"Tools/Actions/PlaceHolder",   NULL, "Placeholder", NULL, NULL, G_CALLBACK(compose_nothing_cb) },
+
+/* Help menu */
+       {"Help/About",          NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) }, 
+};
+
+static GtkToggleActionEntry compose_toggle_entries[] =
+{
+       {"Edit/AutoWrap",               NULL, N_("Aut_o wrapping"), "<shift><control>L", NULL, G_CALLBACK(compose_toggle_autowrap_cb) }, /* TOGGLE */
+       {"Edit/AutoIndent",             NULL, N_("Auto _indent"), NULL, NULL, G_CALLBACK(compose_toggle_autoindent_cb) }, /* TOGGLE */
+       {"Options/Sign",                NULL, N_("Si_gn"), NULL, NULL, G_CALLBACK(compose_toggle_sign_cb) }, /* Toggle */
+       {"Options/Encrypt",             NULL, N_("_Encrypt"), NULL, NULL, G_CALLBACK(compose_toggle_encrypt_cb) }, /* Toggle */
+       {"Options/RequestRetRcpt",      NULL, N_("_Request Return Receipt"), NULL, NULL, G_CALLBACK(compose_toggle_return_receipt_cb) }, /* TOGGLE */
+       {"Options/RemoveReferences",    NULL, N_("Remo_ve references"), NULL, NULL, G_CALLBACK(compose_toggle_remove_refs_cb) }, /* TOGGLE */
+       {"Tools/ShowRuler",             NULL, N_("Show _ruler"), NULL, NULL, G_CALLBACK(compose_toggle_ruler_cb) }, /* Toggle */
+};
+
+static GtkRadioActionEntry compose_radio_rm_entries[] =
+{
+       {"Options/ReplyMode/Normal",    NULL, N_("_Normal"), NULL, NULL, COMPOSE_REPLY }, /* RADIO compose_reply_change_mode_cb */
+       {"Options/ReplyMode/All",       NULL, N_("_All"), NULL, NULL, COMPOSE_REPLY_TO_ALL }, /* RADIO compose_reply_change_mode_cb */
+       {"Options/ReplyMode/Sender",    NULL, N_("_Sender"), NULL, NULL, COMPOSE_REPLY_TO_SENDER }, /* RADIO compose_reply_change_mode_cb */
+       {"Options/ReplyMode/List",      NULL, N_("_Mailing-list"), NULL, NULL, COMPOSE_REPLY_TO_LIST }, /* RADIO compose_reply_change_mode_cb */
+};
+
+static GtkRadioActionEntry compose_radio_prio_entries[] =
+{
+       {"Options/Priority/Highest",    NULL, N_("_Highest"), NULL, NULL, PRIORITY_HIGHEST }, /* RADIO compose_set_priority_cb */
+       {"Options/Priority/High",       NULL, N_("Hi_gh"), NULL, NULL, PRIORITY_HIGH }, /* RADIO compose_set_priority_cb */
+       {"Options/Priority/Normal",     NULL, N_("_Normal"), NULL, NULL, PRIORITY_NORMAL }, /* RADIO compose_set_priority_cb */
+       {"Options/Priority/Low",        NULL, N_("Lo_w"), NULL, NULL, PRIORITY_LOW }, /* RADIO compose_set_priority_cb */
+       {"Options/Priority/Lowest",     NULL, N_("_Lowest"), NULL, NULL, PRIORITY_LOWEST }, /* RADIO compose_set_priority_cb */
+};
+
+static GtkRadioActionEntry compose_radio_enc_entries[] =
+{
+       ENC_ACTION(CS_AUTO, C_AUTO, N_("_Automatic")), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION(CS_US_ASCII, C_US_ASCII, N_("7bit ASCII (US-ASC_II)")), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION(CS_UTF_8, C_UTF_8, N_("Unicode (_UTF-8)")), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Western/"CS_ISO_8859_1, C_ISO_8859_1, "ISO-8859-_1"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Western/"CS_ISO_8859_15, C_ISO_8859_15, "ISO-8859-15"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Western/"CS_WINDOWS_1252, C_WINDOWS_1252, "Windows-1252"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION(CS_ISO_8859_2, C_ISO_8859_2, N_("Central European (ISO-8859-_2)")), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Baltic/"CS_ISO_8859_13, C_ISO_8859_13, "ISO-8859-13"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Baltic/"CS_ISO_8859_4, C_ISO_8859_14, "ISO-8859-_4"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION(CS_ISO_8859_7, C_ISO_8859_7, N_("Greek (ISO-8859-_7)")), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Hebrew/"CS_ISO_8859_8, C_ISO_8859_8, "ISO-8859-_8"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Hebrew/"CS_WINDOWS_1255, C_WINDOWS_1255, "Windows-1255"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Arabic/"CS_ISO_8859_6, C_ISO_8859_6, "ISO-8859-_6"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Arabic/"CS_WINDOWS_1256, C_WINDOWS_1256, "Windows-1256"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION(CS_ISO_8859_9, C_ISO_8859_9, N_("Turkish (ISO-8859-_9)")), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Cyrillic/"CS_ISO_8859_5, C_ISO_8859_5, "ISO-8859-_5"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Cyrillic/"CS_KOI8_R, C_KOI8_R, "KOI8-_R"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Cyrillic/"CS_KOI8_U, C_KOI8_U, "KOI8-_U"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Cyrillic/"CS_WINDOWS_1251, C_WINDOWS_1251, "Windows-1251"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Japanese/"CS_ISO_2022_JP, C_ISO_2022_JP, "ISO-2022-_JP"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Japanese/"CS_ISO_2022_JP_2, C_ISO_2022_JP_2, "ISO-2022-JP-_2"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Japanese/"CS_EUC_JP, C_EUC_JP, "_EUC-JP"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Japanese/"CS_SHIFT_JIS, C_SHIFT_JIS, "_Shift-JIS"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Chinese/"CS_GB2312, C_GB2312, "_GB2312"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Chinese/"CS_GBK, C_GBK, "GB_K"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Chinese/"CS_BIG5, C_BIG5, "_Big5-JP"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Chinese/"CS_EUC_TW, C_EUC_TW, "EUC-_TW"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Korean/"CS_EUC_KR, C_EUC_KR, "_EUC-KR"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Korean/"CS_ISO_2022_KR, C_ISO_2022_KR, "_ISO-2022-KR"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Thai/"CS_TIS_620, C_TIS_620, "_TIS-620-KR"), /* RADIO compose_set_encoding_cb */
+       ENC_ACTION("Thai/"CS_WINDOWS_874, C_WINDOWS_874, "_Windows-874"), /* RADIO compose_set_encoding_cb */
 };
 
 static GtkTargetEntry compose_mime_types[] =
 {
-       {"text/uri-list", 0, 0}
+       {"text/uri-list", 0, 0},
+       {"UTF8_STRING", 0, 0},
+       {"text/plain", 0, 0}
 };
 
 static gboolean compose_put_existing_to_front(MsgInfo *info)
@@ -699,15 +742,136 @@ static gboolean compose_put_existing_to_front(MsgInfo *info)
        return FALSE;
 }
 
+static GdkColor quote_color1 = 
+       {(gulong)0, (gushort)0, (gushort)0, (gushort)0};
+static GdkColor quote_color2 = 
+       {(gulong)0, (gushort)0, (gushort)0, (gushort)0};
+static GdkColor quote_color3 = 
+       {(gulong)0, (gushort)0, (gushort)0, (gushort)0};
+
+static GdkColor quote_bgcolor1 = 
+       {(gulong)0, (gushort)0, (gushort)0, (gushort)0};
+static GdkColor quote_bgcolor2 = 
+       {(gulong)0, (gushort)0, (gushort)0, (gushort)0};
+static GdkColor quote_bgcolor3 = 
+       {(gulong)0, (gushort)0, (gushort)0, (gushort)0};
+
+static GdkColor signature_color = {
+       (gulong)0,
+       (gushort)0x7fff,
+       (gushort)0x7fff,
+       (gushort)0x7fff
+};
+
+static GdkColor uri_color = {
+       (gulong)0,
+       (gushort)0,
+       (gushort)0,
+       (gushort)0
+};
+
+static void compose_create_tags(GtkTextView *text, Compose *compose)
+{
+       GtkTextBuffer *buffer;
+       GdkColor black = {(gulong)0, (gushort)0, (gushort)0, (gushort)0};
+       GdkColormap *cmap;
+       GdkColor color[8];
+       gboolean success[8];
+       int i;
+
+       buffer = gtk_text_view_get_buffer(text);
+
+       if (prefs_common.enable_color) {
+               /* grab the quote colors, converting from an int to a GdkColor */
+               gtkut_convert_int_to_gdk_color(prefs_common.quote_level1_col,
+                                              &quote_color1);
+               gtkut_convert_int_to_gdk_color(prefs_common.quote_level2_col,
+                                              &quote_color2);
+               gtkut_convert_int_to_gdk_color(prefs_common.quote_level3_col,
+                                              &quote_color3);
+               gtkut_convert_int_to_gdk_color(prefs_common.quote_level1_bgcol,
+                                              &quote_bgcolor1);
+               gtkut_convert_int_to_gdk_color(prefs_common.quote_level2_bgcol,
+                                              &quote_bgcolor2);
+               gtkut_convert_int_to_gdk_color(prefs_common.quote_level3_bgcol,
+                                              &quote_bgcolor3);
+               gtkut_convert_int_to_gdk_color(prefs_common.signature_col,
+                                              &signature_color);
+               gtkut_convert_int_to_gdk_color(prefs_common.uri_col,
+                                              &uri_color);
+       } else {
+               signature_color = quote_color1 = quote_color2 = quote_color3 = 
+                       quote_bgcolor1 = quote_bgcolor2 = quote_bgcolor3 = uri_color = black;
+       }
+
+       if (prefs_common.enable_color && prefs_common.enable_bgcolor) {
+               compose->quote0_tag = gtk_text_buffer_create_tag(buffer, "quote0",
+                                          "foreground-gdk", &quote_color1,
+                                          "paragraph-background-gdk", &quote_bgcolor1,
+                                          NULL);
+               compose->quote1_tag = gtk_text_buffer_create_tag(buffer, "quote1",
+                                          "foreground-gdk", &quote_color2,
+                                          "paragraph-background-gdk", &quote_bgcolor2,
+                                          NULL);
+               compose->quote2_tag = gtk_text_buffer_create_tag(buffer, "quote2",
+                                          "foreground-gdk", &quote_color3,
+                                          "paragraph-background-gdk", &quote_bgcolor3,
+                                          NULL);
+       } else {
+               compose->quote0_tag = gtk_text_buffer_create_tag(buffer, "quote0",
+                                          "foreground-gdk", &quote_color1,
+                                          NULL);
+               compose->quote1_tag = gtk_text_buffer_create_tag(buffer, "quote1",
+                                          "foreground-gdk", &quote_color2,
+                                          NULL);
+               compose->quote2_tag = gtk_text_buffer_create_tag(buffer, "quote2",
+                                          "foreground-gdk", &quote_color3,
+                                          NULL);
+       }
+       
+       compose->signature_tag = gtk_text_buffer_create_tag(buffer, "signature",
+                                  "foreground-gdk", &signature_color,
+                                  NULL);
+       
+       compose->uri_tag = gtk_text_buffer_create_tag(buffer, "link",
+                                       "foreground-gdk", &uri_color,
+                                        NULL);
+       compose->no_wrap_tag = gtk_text_buffer_create_tag(buffer, "no_wrap", NULL);
+       compose->no_join_tag = gtk_text_buffer_create_tag(buffer, "no_join", NULL);
+
+       color[0] = quote_color1;
+       color[1] = quote_color2;
+       color[2] = quote_color3;
+       color[3] = quote_bgcolor1;
+       color[4] = quote_bgcolor2;
+       color[5] = quote_bgcolor3;
+       color[6] = signature_color;
+       color[7] = uri_color;
+       cmap = gdk_drawable_get_colormap(compose->window->window);
+       gdk_colormap_alloc_colors(cmap, color, 8, FALSE, TRUE, success);
+
+       for (i = 0; i < 8; i++) {
+               if (success[i] == FALSE) {
+                       GtkStyle *style;
+
+                       g_warning("Compose: color allocation failed.\n");
+                       style = gtk_widget_get_style(GTK_WIDGET(text));
+                       quote_color1 = quote_color2 = quote_color3 = 
+                               quote_bgcolor1 = quote_bgcolor2 = quote_bgcolor3 = 
+                               signature_color = uri_color = black;
+               }
+       }
+}
+
 Compose *compose_new(PrefsAccount *account, const gchar *mailto,
                     GPtrArray *attach_files)
 {
        return compose_generic_new(account, mailto, NULL, attach_files, NULL);
 }
 
-Compose *compose_new_with_folderitem(PrefsAccount *account, FolderItem *item)
+Compose *compose_new_with_folderitem(PrefsAccount *account, FolderItem *item, const gchar *mailto)
 {
-       return compose_generic_new(account, NULL, item, NULL, NULL);
+       return compose_generic_new(account, mailto, item, NULL, NULL);
 }
 
 Compose *compose_new_with_list( PrefsAccount *account, GList *listAddress )
@@ -715,65 +879,248 @@ Compose *compose_new_with_list( PrefsAccount *account, GList *listAddress )
        return compose_generic_new( account, NULL, NULL, NULL, listAddress );
 }
 
+#define SCROLL_TO_CURSOR(compose) {                            \
+       GtkTextMark *cmark = gtk_text_buffer_get_insert(        \
+               gtk_text_view_get_buffer(                       \
+                       GTK_TEXT_VIEW(compose->text)));         \
+       gtk_text_view_scroll_mark_onscreen(                     \
+               GTK_TEXT_VIEW(compose->text),                   \
+               cmark);                                         \
+}
+
+static void compose_set_save_to(Compose *compose, const gchar *folderidentifier)
+{
+       GtkEditable *entry;
+       if (folderidentifier) {
+               combobox_unset_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo));
+               prefs_common.compose_save_to_history = add_history(
+                               prefs_common.compose_save_to_history, folderidentifier);
+               combobox_set_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo),
+                               prefs_common.compose_save_to_history);
+       }
+
+       entry = GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(compose->savemsg_combo)));
+       if (folderidentifier)
+               gtk_entry_set_text(GTK_ENTRY(entry), folderidentifier);
+       else
+               gtk_entry_set_text(GTK_ENTRY(entry), "");
+}
+
+static gchar *compose_get_save_to(Compose *compose)
+{
+       GtkEditable *entry;
+       gchar *result = NULL;
+       entry = GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(compose->savemsg_combo)));
+       result = gtk_editable_get_chars(entry, 0, -1);
+       
+       if (result) {
+               combobox_unset_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo));
+               prefs_common.compose_save_to_history = add_history(
+                               prefs_common.compose_save_to_history, result);
+               combobox_set_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo),
+                               prefs_common.compose_save_to_history);
+       }
+       return result;
+}
+
 Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderItem *item,
                             GPtrArray *attach_files, GList *listAddress )
 {
        Compose *compose;
-       GtkSText *text;
-       GtkItemFactory *ifactory;
-
-       if (item && item->prefs && item->prefs->enable_default_account)
+       GtkTextView *textview;
+       GtkTextBuffer *textbuf;
+       GtkTextIter iter;
+       const gchar *subject_format = NULL;
+       const gchar *body_format = NULL;
+       gchar *mailto_from = NULL;
+       PrefsAccount *mailto_account = NULL;
+       MsgInfo* dummyinfo = NULL;
+
+       /* check if mailto defines a from */
+       if (mailto && *mailto != '\0') {
+               scan_mailto_url(mailto, &mailto_from, NULL, NULL, NULL, NULL, NULL, NULL);
+               /* mailto defines a from, check if we can get account prefs from it,
+                  if not, the account prefs will be guessed using other ways, but we'll keep
+                  the from anyway */
+               if (mailto_from)
+                       mailto_account = account_find_from_address(mailto_from, TRUE);
+               if (mailto_account)
+                       account = mailto_account;
+       }
+
+       /* if no account prefs set from mailto, set if from folder prefs (if any) */
+       if (!mailto_account && item && item->prefs && item->prefs->enable_default_account)
                account = account_find_from_id(item->prefs->default_account);
 
+       /* if no account prefs set, fallback to the current one */
        if (!account) account = cur_account;
-       g_return_val_if_fail(account != NULL, NULL);
+       cm_return_val_if_fail(account != NULL, NULL);
+
+       compose = compose_create(account, item, COMPOSE_NEW, FALSE);
+
+       /* override from name if mailto asked for it */
+       if (mailto_from) {
+               gtk_entry_set_text(GTK_ENTRY(compose->from_name), mailto_from);
+               g_free(mailto_from);
+       } else
+               /* override from name according to folder properties */
+               if (item && item->prefs &&
+                       item->prefs->compose_with_format &&
+                       item->prefs->compose_override_from_format &&
+                       *item->prefs->compose_override_from_format != '\0') {
+
+                       gchar *tmp = NULL;
+                       gchar *buf = NULL;
+
+                       dummyinfo = compose_msginfo_new_from_compose(compose);
+
+                       /* decode \-escape sequences in the internal representation of the quote format */
+                       tmp = malloc(strlen(item->prefs->compose_override_from_format)+1);
+                       pref_get_unescaped_pref(tmp, item->prefs->compose_override_from_format);
+
+#ifdef USE_ENCHANT
+                       quote_fmt_init(dummyinfo, NULL, NULL, FALSE, compose->account, FALSE,
+                                       compose->gtkaspell);
+#else
+                       quote_fmt_init(dummyinfo, NULL, NULL, FALSE, compose->account, FALSE);
+#endif
+                       quote_fmt_scan_string(tmp);
+                       quote_fmt_parse();
+
+                       buf = quote_fmt_get_buffer();
+                       if (buf == NULL)
+                               alertpanel_error(_("New message From format error."));
+                       else
+                               gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
+                       quote_fmt_reset_vartable();
 
-       compose = compose_create(account, COMPOSE_NEW);
-       ifactory = gtk_item_factory_from_widget(compose->menubar);
+                       g_free(tmp);
+               }
 
        compose->replyinfo = NULL;
        compose->fwdinfo   = NULL;
 
-       text = GTK_STEXT(compose->text);
-       gtk_stext_freeze(text);
+       textview = GTK_TEXT_VIEW(compose->text);
+       textbuf = gtk_text_view_get_buffer(textview);
+       compose_create_tags(textview, compose);
 
-#ifdef USE_ASPELL
-       if (item && item->prefs && item->prefs->enable_default_dictionary &&
-           compose->gtkaspell) 
-               gtkaspell_change_dict(compose->gtkaspell, 
-                   item->prefs->default_dictionary);
+       undo_block(compose->undostruct);
+#ifdef USE_ENCHANT
+       compose_set_dictionaries_from_folder_prefs(compose, item);
 #endif
 
        if (account->auto_sig)
                compose_insert_sig(compose, FALSE);
-       gtk_editable_set_position(GTK_EDITABLE(text), 0);
-       gtk_stext_set_point(text, 0);
-
-       gtk_stext_thaw(text);
+       gtk_text_buffer_get_start_iter(textbuf, &iter);
+       gtk_text_buffer_place_cursor(textbuf, &iter);
 
        if (account->protocol != A_NNTP) {
                if (mailto && *mailto != '\0') {
-                       compose_entries_set(compose, mailto);
+                       compose_entries_set(compose, mailto, COMPOSE_TO);
 
-               } else if (item && item->prefs->enable_default_to) {
+               } else if (item && item->prefs && item->prefs->enable_default_to) {
                        compose_entry_append(compose, item->prefs->default_to, COMPOSE_TO);
                        compose_entry_mark_default_to(compose, item->prefs->default_to);
                }
                if (item && item->ret_rcpt) {
-                       menu_set_active(ifactory, "/Options/Request Return Receipt", TRUE);
+                       cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/RequestRetRcpt", TRUE);
                }
        } else {
-               if (mailto) {
-                       compose_entry_append(compose, mailto, COMPOSE_NEWSGROUPS);
+               if (mailto && *mailto != '\0') {
+                       if (!strchr(mailto, '@'))
+                               compose_entries_set(compose, mailto, COMPOSE_NEWSGROUPS);
+                       else
+                               compose_entries_set(compose, mailto, COMPOSE_TO);
+               } else if (item && FOLDER_CLASS(item->folder) == news_get_class()) {
+                       compose_entry_append(compose, item->path, COMPOSE_NEWSGROUPS);
                }
                /*
                 * CLAWS: just don't allow return receipt request, even if the user
                 * may want to send an email. simple but foolproof.
                 */
-               menu_set_sensitive(ifactory, "/Options/Request Return Receipt", FALSE); 
+               cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options/RequestRetRcpt", FALSE); 
        }
        compose_add_field_list( compose, listAddress );
 
+       if (item && item->prefs && item->prefs->compose_with_format) {
+               subject_format = item->prefs->compose_subject_format;
+               body_format = item->prefs->compose_body_format;
+       } else if (account->compose_with_format) {
+               subject_format = account->compose_subject_format;
+               body_format = account->compose_body_format;
+       } else if (prefs_common.compose_with_format) {
+               subject_format = prefs_common.compose_subject_format;
+               body_format = prefs_common.compose_body_format;
+       }
+
+       if (subject_format || body_format) {
+
+               if ( subject_format
+                        && *subject_format != '\0' )
+               {
+                       gchar *subject = NULL;
+                       gchar *tmp = NULL;
+                       gchar *buf = NULL;
+
+                       if (!dummyinfo)
+                               dummyinfo = compose_msginfo_new_from_compose(compose);
+
+                       /* decode \-escape sequences in the internal representation of the quote format */
+                       tmp = malloc(strlen(subject_format)+1);
+                       pref_get_unescaped_pref(tmp, subject_format);
+
+                       subject = gtk_editable_get_chars(GTK_EDITABLE(compose->subject_entry), 0, -1);
+#ifdef USE_ENCHANT
+                       quote_fmt_init(dummyinfo, NULL, subject, FALSE, compose->account, FALSE,
+                                       compose->gtkaspell);
+#else
+                       quote_fmt_init(dummyinfo, NULL, subject, FALSE, compose->account, FALSE);
+#endif
+                       quote_fmt_scan_string(tmp);
+                       quote_fmt_parse();
+
+                       buf = quote_fmt_get_buffer();
+                       if (buf == NULL)
+                               alertpanel_error(_("New message subject format error."));
+                       else
+                               gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf);
+                       compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
+                       quote_fmt_reset_vartable();
+
+                       g_free(subject);
+                       g_free(tmp);
+               }
+
+               if ( body_format
+                        && *body_format != '\0' )
+               {
+                       GtkTextView *text;
+                       GtkTextBuffer *buffer;
+                       GtkTextIter start, end;
+                       gchar *tmp = NULL;
+
+                       if (!dummyinfo)
+                               dummyinfo = compose_msginfo_new_from_compose(compose);
+
+                       text = GTK_TEXT_VIEW(compose->text);
+                       buffer = gtk_text_view_get_buffer(text);
+                       gtk_text_buffer_get_start_iter(buffer, &start);
+                       gtk_text_buffer_get_iter_at_offset(buffer, &end, -1);
+                       tmp = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
+
+                       compose_quote_fmt(compose, dummyinfo,
+                                         body_format,
+                                         NULL, tmp, FALSE, TRUE,
+                                                 _("New message body format error at line %d."));
+                       compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
+                       quote_fmt_reset_vartable();
+
+                       g_free(tmp);
+               }
+
+       }
+       procmsg_msginfo_free( dummyinfo );
+
        if (attach_files) {
                gint i;
                gchar *file;
@@ -792,187 +1139,324 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI
 
                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);
+               compose_set_save_to(compose, folderidentifier);
                g_free(folderidentifier);
        }
        
        gtk_widget_grab_focus(compose->header_last->entry);
 
+       undo_unblock(compose->undostruct);
+
        if (prefs_common.auto_exteditor)
                compose_exec_ext_editor(compose);
 
+       compose->draft_timeout_tag = -1;
+       SCROLL_TO_CURSOR(compose);
+
+       compose->modified = FALSE;
+       compose_set_title(compose);
         return compose;
 }
 
-/*
-Compose *compose_new_followup_and_replyto(PrefsAccount *account,
-                                          const gchar *followupto, gchar * to)
+static void compose_force_encryption(Compose *compose, PrefsAccount *account,
+               gboolean override_pref, const gchar *system)
 {
-       Compose *compose;
+       const gchar *privacy = NULL;
+
+       cm_return_if_fail(compose != NULL);
+       cm_return_if_fail(account != NULL);
 
-       if (!account) account = cur_account;
-       g_return_val_if_fail(account != NULL, NULL);
-       g_return_val_if_fail(account->protocol != A_NNTP, NULL);
+       if (override_pref == FALSE && account->default_encrypt_reply == FALSE)
+               return;
 
-       compose = compose_create(account, COMPOSE_NEW);
+       if (system)
+               privacy = system;
+       else if (account->default_privacy_system
+       &&  strlen(account->default_privacy_system)) {
+               privacy = account->default_privacy_system;
+       } else {
+               GSList *privacy_avail = privacy_get_system_ids();
+               if (privacy_avail && g_slist_length(privacy_avail)) {
+                       privacy = (gchar *)(privacy_avail->data);
+               }
+       }
+       if (privacy != NULL) {
+               if (system) {
+                       g_free(compose->privacy_system);
+                       compose->privacy_system = NULL;
+               }
+               if (compose->privacy_system == NULL)
+                       compose->privacy_system = g_strdup(privacy);
+               else if (*(compose->privacy_system) == '\0') {
+                       g_free(compose->privacy_system);
+                       compose->privacy_system = g_strdup(privacy);
+               }
+               compose_update_privacy_system_menu_item(compose, FALSE);
+               compose_use_encryption(compose, TRUE);
+       }
+}      
 
-       if (prefs_common.auto_sig)
-               compose_insert_sig(compose);
-       gtk_editable_set_position(GTK_EDITABLE(compose->text), 0);
-       gtk_stext_set_point(GTK_STEXT(compose->text), 0);
+static void compose_force_signing(Compose *compose, PrefsAccount *account, const gchar *system)
+{
+       const gchar *privacy = NULL;
 
-       compose_entry_append(compose, to, COMPOSE_TO);
-       compose_entry_append(compose, followupto, COMPOSE_NEWSGROUPS);
-       gtk_widget_grab_focus(compose->subject_entry);
+       if (system)
+               privacy = system;
+       else if (account->default_privacy_system
+       &&  strlen(account->default_privacy_system)) {
+               privacy = account->default_privacy_system;
+       } else {
+               GSList *privacy_avail = privacy_get_system_ids();
+               if (privacy_avail && g_slist_length(privacy_avail)) {
+                       privacy = (gchar *)(privacy_avail->data);
+               }
+       }
 
-       return compose;
-}
-*/
+       if (privacy != NULL) {
+               if (system) {
+                       g_free(compose->privacy_system);
+                       compose->privacy_system = NULL;
+               }
+               if (compose->privacy_system == NULL)
+                       compose->privacy_system = g_strdup(privacy);
+               compose_update_privacy_system_menu_item(compose, FALSE);
+               compose_use_signing(compose, TRUE);
+       }
+}      
 
-void compose_reply_mode(ComposeMode mode, GSList *msginfo_list, gchar *body)
+static Compose *compose_reply_mode(ComposeMode mode, GSList *msginfo_list, gchar *body)
 {
        MsgInfo *msginfo;
        guint list_len;
-
-       g_return_if_fail(msginfo_list != NULL);
+       Compose *compose = NULL;
+       
+       cm_return_val_if_fail(msginfo_list != NULL, NULL);
 
        msginfo = (MsgInfo*)g_slist_nth_data(msginfo_list, 0);
-       g_return_if_fail(msginfo != NULL);
+       cm_return_val_if_fail(msginfo != NULL, NULL);
 
        list_len = g_slist_length(msginfo_list);
 
        switch (mode) {
        case COMPOSE_REPLY:
-               compose_reply(msginfo, prefs_common.reply_with_quote,
+               compose = compose_reply(msginfo, COMPOSE_QUOTE_CHECK,
                              FALSE, prefs_common.default_reply_list, FALSE, body);
                break;
        case COMPOSE_REPLY_WITH_QUOTE:
-               compose_reply(msginfo, TRUE, FALSE, prefs_common.default_reply_list, FALSE, body);
+               compose = compose_reply(msginfo, COMPOSE_QUOTE_FORCED, 
+                       FALSE, prefs_common.default_reply_list, FALSE, body);
                break;
        case COMPOSE_REPLY_WITHOUT_QUOTE:
-               compose_reply(msginfo, FALSE, FALSE, prefs_common.default_reply_list, FALSE, NULL);
+               compose = compose_reply(msginfo, COMPOSE_QUOTE_SKIP, 
+                       FALSE, prefs_common.default_reply_list, FALSE, NULL);
                break;
        case COMPOSE_REPLY_TO_SENDER:
-               compose_reply(msginfo, prefs_common.reply_with_quote,
+               compose = compose_reply(msginfo, COMPOSE_QUOTE_CHECK,
                              FALSE, FALSE, TRUE, body);
                break;
        case COMPOSE_FOLLOWUP_AND_REPLY_TO:
-               compose_followup_and_reply_to(msginfo,
-                                             prefs_common.reply_with_quote,
+               compose = compose_followup_and_reply_to(msginfo,
+                                             COMPOSE_QUOTE_CHECK,
                                              FALSE, FALSE, body);
                break;
        case COMPOSE_REPLY_TO_SENDER_WITH_QUOTE:
-               compose_reply(msginfo, TRUE, FALSE, FALSE, TRUE, body);
+               compose = compose_reply(msginfo, COMPOSE_QUOTE_FORCED, 
+                       FALSE, FALSE, TRUE, body);
                break;
        case COMPOSE_REPLY_TO_SENDER_WITHOUT_QUOTE:
-               compose_reply(msginfo, FALSE, FALSE, FALSE, TRUE, NULL);
+               compose = compose_reply(msginfo, COMPOSE_QUOTE_SKIP, 
+                       FALSE, FALSE, TRUE, NULL);
                break;
        case COMPOSE_REPLY_TO_ALL:
-               compose_reply(msginfo, prefs_common.reply_with_quote,
-                             TRUE, FALSE, FALSE, body);
+               compose = compose_reply(msginfo, COMPOSE_QUOTE_CHECK,
+                       TRUE, FALSE, FALSE, body);
                break;
        case COMPOSE_REPLY_TO_ALL_WITH_QUOTE:
-               compose_reply(msginfo, TRUE, TRUE, FALSE, FALSE, body);
+               compose = compose_reply(msginfo, COMPOSE_QUOTE_FORCED, 
+                       TRUE, FALSE, FALSE, body);
                break;
        case COMPOSE_REPLY_TO_ALL_WITHOUT_QUOTE:
-               compose_reply(msginfo, FALSE, TRUE, FALSE, FALSE, NULL);
+               compose = compose_reply(msginfo, COMPOSE_QUOTE_SKIP, 
+                       TRUE, FALSE, FALSE, NULL);
                break;
        case COMPOSE_REPLY_TO_LIST:
-               compose_reply(msginfo, prefs_common.reply_with_quote,
-                             FALSE, TRUE, FALSE, body);
+               compose = compose_reply(msginfo, COMPOSE_QUOTE_CHECK,
+                       FALSE, TRUE, FALSE, body);
                break;
        case COMPOSE_REPLY_TO_LIST_WITH_QUOTE:
-               compose_reply(msginfo, TRUE, FALSE, TRUE, FALSE, body);
+               compose = compose_reply(msginfo, COMPOSE_QUOTE_FORCED, 
+                       FALSE, TRUE, FALSE, body);
                break;
        case COMPOSE_REPLY_TO_LIST_WITHOUT_QUOTE:
-               compose_reply(msginfo, FALSE, FALSE, TRUE, FALSE, NULL);
+               compose = compose_reply(msginfo, COMPOSE_QUOTE_SKIP, 
+                       FALSE, TRUE, FALSE, NULL);
                break;
        case COMPOSE_FORWARD:
                if (prefs_common.forward_as_attachment) {
-                       compose_reply_mode(COMPOSE_FORWARD_AS_ATTACH, msginfo_list, body);
-                       return;
+                       compose = compose_reply_mode(COMPOSE_FORWARD_AS_ATTACH, msginfo_list, body);
+                       return compose;
                } else {
-                       compose_reply_mode(COMPOSE_FORWARD_INLINE, msginfo_list, body);
-                       return;
+                       compose = compose_reply_mode(COMPOSE_FORWARD_INLINE, msginfo_list, body);
+                       return compose;
                }
                break;
        case COMPOSE_FORWARD_INLINE:
                /* check if we reply to more than one Message */
                if (list_len == 1) {
-                       compose_forward(NULL, msginfo, FALSE, body, FALSE);
+                       compose = compose_forward(NULL, msginfo, FALSE, body, FALSE, FALSE);
                        break;
                } 
                /* more messages FALL THROUGH */
        case COMPOSE_FORWARD_AS_ATTACH:
-               compose_forward_multiple(NULL, msginfo_list);
+               compose = compose_forward_multiple(NULL, msginfo_list);
                break;
        case COMPOSE_REDIRECT:
-               compose_redirect(NULL, msginfo);
+               compose = compose_redirect(NULL, msginfo, FALSE);
+               break;
+       default:
+               g_warning("compose_reply_mode(): invalid Compose Mode: %d\n", mode);
+       }
+       
+       if (compose == NULL) {
+               alertpanel_error(_("Unable to reply. The original email probably doesn't exist."));
+               return NULL;
+       }
+
+       compose->rmode = mode;
+       switch (compose->rmode) {
+       case COMPOSE_REPLY:
+       case COMPOSE_REPLY_WITH_QUOTE:
+       case COMPOSE_REPLY_WITHOUT_QUOTE:
+       case COMPOSE_FOLLOWUP_AND_REPLY_TO:
+               debug_print("reply mode Normal\n");
+               cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/ReplyMode/Normal", TRUE);
+               compose_reply_change_mode(compose, COMPOSE_REPLY); /* force update */
+               break;
+       case COMPOSE_REPLY_TO_SENDER:
+       case COMPOSE_REPLY_TO_SENDER_WITH_QUOTE:
+       case COMPOSE_REPLY_TO_SENDER_WITHOUT_QUOTE:
+               debug_print("reply mode Sender\n");
+               cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/ReplyMode/Sender", TRUE);
+               break;
+       case COMPOSE_REPLY_TO_ALL:
+       case COMPOSE_REPLY_TO_ALL_WITH_QUOTE:
+       case COMPOSE_REPLY_TO_ALL_WITHOUT_QUOTE:
+               debug_print("reply mode All\n");
+               cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/ReplyMode/All", TRUE);
+               break;
+       case COMPOSE_REPLY_TO_LIST:
+       case COMPOSE_REPLY_TO_LIST_WITH_QUOTE:
+       case COMPOSE_REPLY_TO_LIST_WITHOUT_QUOTE:
+               debug_print("reply mode List\n");
+               cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/ReplyMode/List", TRUE);
                break;
        default:
-               g_warning("compose_reply(): invalid Compose Mode: %d\n", mode);
+               break;
        }
+       return compose;
 }
 
-void compose_reply(MsgInfo *msginfo, gboolean quote, gboolean to_all,
-                  gboolean to_ml, gboolean to_sender, 
+static Compose *compose_reply(MsgInfo *msginfo,
+                                  ComposeQuoteMode quote_mode,
+                                  gboolean to_all,
+                                  gboolean to_ml,
+                                  gboolean to_sender, 
                   const gchar *body)
 {
-       compose_generic_reply(msginfo, quote, to_all, to_ml, 
+       return compose_generic_reply(msginfo, quote_mode, to_all, to_ml, 
                              to_sender, FALSE, body);
 }
 
-void compose_followup_and_reply_to(MsgInfo *msginfo, gboolean quote,
+static Compose *compose_followup_and_reply_to(MsgInfo *msginfo,
+                                  ComposeQuoteMode quote_mode,
                                   gboolean to_all,
                                   gboolean to_sender,
                                   const gchar *body)
 {
-       compose_generic_reply(msginfo, quote, to_all, FALSE, 
+       return compose_generic_reply(msginfo, quote_mode, to_all, FALSE, 
                              to_sender, TRUE, body);
 }
 
-static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
+static void compose_extract_original_charset(Compose *compose)
+{
+       MsgInfo *info = NULL;
+       if (compose->replyinfo) {
+               info = compose->replyinfo;
+       } else if (compose->fwdinfo) {
+               info = compose->fwdinfo;
+       } else if (compose->targetinfo) {
+               info = compose->targetinfo;
+       }
+       if (info) {
+               MimeInfo *mimeinfo = procmime_scan_message_short(info);
+               MimeInfo *partinfo = mimeinfo;
+               while (partinfo && partinfo->type != MIMETYPE_TEXT)
+                       partinfo = procmime_mimeinfo_next(partinfo);
+               if (partinfo) {
+                       compose->orig_charset = 
+                               g_strdup(procmime_mimeinfo_get_parameter(
+                                               partinfo, "charset"));
+               }
+               procmime_mimeinfo_free_all(mimeinfo);
+       }
+}
+
+#define SIGNAL_BLOCK(buffer) {                                 \
+       g_signal_handlers_block_by_func(G_OBJECT(buffer),       \
+                               G_CALLBACK(compose_changed_cb), \
+                               compose);                       \
+       g_signal_handlers_block_by_func(G_OBJECT(buffer),       \
+                               G_CALLBACK(text_inserted),      \
+                               compose);                       \
+}
+
+#define SIGNAL_UNBLOCK(buffer) {                               \
+       g_signal_handlers_unblock_by_func(G_OBJECT(buffer),     \
+                               G_CALLBACK(compose_changed_cb), \
+                               compose);                       \
+       g_signal_handlers_unblock_by_func(G_OBJECT(buffer),     \
+                               G_CALLBACK(text_inserted),      \
+                               compose);                       \
+}
+
+static Compose *compose_generic_reply(MsgInfo *msginfo,
+                                 ComposeQuoteMode quote_mode,
                                  gboolean to_all, gboolean to_ml,
                                  gboolean to_sender,
                                  gboolean followup_and_reply_to,
                                  const gchar *body)
 {
-       GtkItemFactory *ifactory;
        Compose *compose;
        PrefsAccount *account = NULL;
-       PrefsAccount *reply_account;
-       GtkSText *text;
-
-       g_return_if_fail(msginfo != NULL);
-       g_return_if_fail(msginfo->folder != NULL);
+       GtkTextView *textview;
+       GtkTextBuffer *textbuf;
+       gboolean quote = FALSE;
+       const gchar *qmark = NULL;
+       const gchar *body_fmt = NULL;
+       gchar *s_system = NULL;
+       START_TIMING("");
+       cm_return_val_if_fail(msginfo != NULL, NULL);
+       cm_return_val_if_fail(msginfo->folder != NULL, NULL);
 
        account = account_get_reply_account(msginfo, prefs_common.reply_account_autosel);
-       
-       g_return_if_fail(account != NULL);
-
-       if (to_sender && account->protocol == A_NNTP &&
-           !followup_and_reply_to) {
-               reply_account =
-                       account_find_from_address(account->address);
-               if (!reply_account)
-                       reply_account = compose_current_mail_account();
-               if (!reply_account)
-                       return;
-       } else
-               reply_account = account;
 
-       compose = compose_create(account, COMPOSE_REPLY);
-       ifactory = gtk_item_factory_from_widget(compose->menubar);
+       cm_return_val_if_fail(account != NULL, NULL);
+
+       compose = compose_create(account, msginfo->folder, COMPOSE_REPLY, FALSE);
+
+       compose->updating = TRUE;
 
-       menu_set_active(ifactory, "/Options/Remove references", FALSE);
-       menu_set_sensitive(ifactory, "/Options/Remove references", TRUE);
+       cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/RemoveReferences", FALSE);
+       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options/RemoveReferences", TRUE);
 
        compose->replyinfo = procmsg_msginfo_get_full_info(msginfo);
        if (!compose->replyinfo)
                compose->replyinfo = procmsg_msginfo_copy(msginfo);
 
+       compose_extract_original_charset(compose);
+       
        if (msginfo->folder && msginfo->folder->ret_rcpt)
-               menu_set_active(ifactory, "/Options/Request Return Receipt", TRUE);
+               cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/RequestRetRcpt", TRUE);
 
        /* Set save folder */
        if (msginfo->folder && msginfo->folder->prefs && msginfo->folder->prefs->save_copy_to_folder) {
@@ -980,63 +1464,131 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
 
                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);
+               compose_set_save_to(compose, folderidentifier);
                g_free(folderidentifier);
        }
 
-       if (compose_parse_header(compose, msginfo) < 0) return;
-       compose_reply_set_entry(compose, msginfo, to_all, to_ml, 
-                               to_sender, followup_and_reply_to);
-       compose_show_first_last_header(compose, TRUE);
+       if (compose_parse_header(compose, msginfo) < 0) {
+               compose->updating = FALSE;
+               compose_destroy(compose);
+               return NULL;
+       }
 
-       text = GTK_STEXT(compose->text);
-       gtk_stext_freeze(text);
+       /* override from name according to folder properties */
+       if (msginfo->folder && msginfo->folder->prefs &&
+               msginfo->folder->prefs->reply_with_format &&
+               msginfo->folder->prefs->reply_override_from_format &&
+               *msginfo->folder->prefs->reply_override_from_format != '\0') {
 
-#ifdef USE_ASPELL
-       if (msginfo->folder && msginfo->folder->prefs && 
-           msginfo->folder->prefs && 
-           msginfo->folder->prefs->enable_default_dictionary &&
-           compose->gtkaspell)
-               gtkaspell_change_dict(compose->gtkaspell, 
-                   msginfo->folder->prefs->default_dictionary);
-#endif
+               gchar *tmp = NULL;
+               gchar *buf = NULL;
 
-       if (quote) {
-               gchar *qmark;
+               /* decode \-escape sequences in the internal representation of the quote format */
+               tmp = malloc(strlen(msginfo->folder->prefs->reply_override_from_format)+1);
+               pref_get_unescaped_pref(tmp, msginfo->folder->prefs->reply_override_from_format);
 
-               if (prefs_common.quotemark && *prefs_common.quotemark)
-                       qmark = prefs_common.quotemark;
+#ifdef USE_ENCHANT
+               quote_fmt_init(compose->replyinfo, NULL, NULL, FALSE, compose->account, FALSE,
+                               compose->gtkaspell);
+#else
+               quote_fmt_init(compose->replyinfo, NULL, NULL, FALSE, compose->account, FALSE);
+#endif
+               quote_fmt_scan_string(tmp);
+               quote_fmt_parse();
+
+               buf = quote_fmt_get_buffer();
+               if (buf == NULL)
+                       alertpanel_error(_("Message reply From format error."));
                else
-                       qmark = "> ";
+                       gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
+               quote_fmt_reset_vartable();
 
-               compose_quote_fmt(compose, compose->replyinfo,
-                                 prefs_common.quotefmt,
-                                 qmark, body);
+               g_free(tmp);
        }
 
-       if (account->auto_sig)
-               compose_insert_sig(compose, FALSE);
+       textview = (GTK_TEXT_VIEW(compose->text));
+       textbuf = gtk_text_view_get_buffer(textview);
+       compose_create_tags(textview, compose);
 
-       /* Must thaw here, otherwise the GtkSTextEdit will become confused 
-        * when positioning cursor */
-       gtk_stext_thaw(text);
+       undo_block(compose->undostruct);
+#ifdef USE_ENCHANT
+               compose_set_dictionaries_from_folder_prefs(compose, msginfo->folder);
+#endif
 
-       if (quote) {
-               gtk_editable_set_position
-                       (GTK_EDITABLE(text), quote_fmt_get_cursor_pos());
-               gtk_stext_set_point(text, quote_fmt_get_cursor_pos());
-       }
+       if (quote_mode == COMPOSE_QUOTE_FORCED ||
+                       (quote_mode == COMPOSE_QUOTE_CHECK && prefs_common.reply_with_quote)) {
+               /* use the reply format of folder (if enabled), or the account's one
+                  (if enabled) or fallback to the global reply format, which is always
+                  enabled (even if empty), and use the relevant quotemark */
+               quote = TRUE;
+               if (msginfo->folder && msginfo->folder->prefs &&
+                               msginfo->folder->prefs->reply_with_format) {
+                       qmark = msginfo->folder->prefs->reply_quotemark;
+                       body_fmt = msginfo->folder->prefs->reply_body_format;
+
+               } else if (account->reply_with_format) {
+                       qmark = account->reply_quotemark;
+                       body_fmt = account->reply_body_format;
 
-       if (quote && prefs_common.linewrap_quote) {
-               gtk_stext_freeze(text);
-               compose_wrap_line_all(compose);
-               gtk_stext_thaw(text);
+               } else {
+                       qmark = prefs_common.quotemark;
+                       if (prefs_common.quotefmt && *prefs_common.quotefmt)
+                               body_fmt = gettext(prefs_common.quotefmt);
+                       else
+                               body_fmt = "";
+               }
+       }
+
+       if (quote) {
+               /* empty quotemark is not allowed */
+               if (qmark == NULL || *qmark == '\0')
+                       qmark = "> ";
+               compose_quote_fmt(compose, compose->replyinfo,
+                                 body_fmt, qmark, body, FALSE, TRUE,
+                                         _("Message reply format error at line %d."));
+               compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
+               quote_fmt_reset_vartable();
+       }
+
+       if (MSG_IS_ENCRYPTED(compose->replyinfo->flags)) {
+               compose_force_encryption(compose, account, FALSE, s_system);
+       }
+
+       privacy_msginfo_get_signed_state(compose->replyinfo, &s_system);
+       if (MSG_IS_SIGNED(compose->replyinfo->flags) && account->default_sign_reply) {
+               compose_force_signing(compose, account, s_system);
        }
+       g_free(s_system);
+
+       SIGNAL_BLOCK(textbuf);
+       
+       if (account->auto_sig)
+               compose_insert_sig(compose, FALSE);
+
+       compose_wrap_all(compose);
 
+       SIGNAL_UNBLOCK(textbuf);
+       
        gtk_widget_grab_focus(compose->text);
 
+       undo_unblock(compose->undostruct);
+
        if (prefs_common.auto_exteditor)
                compose_exec_ext_editor(compose);
+               
+       compose->modified = FALSE;
+       compose_set_title(compose);
+
+       compose->updating = FALSE;
+       compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
+       SCROLL_TO_CURSOR(compose);
+       
+       if (compose->deferred_destroy) {
+               compose_destroy(compose);
+               return NULL;
+       }
+       END_TIMING();
+       return compose;
 }
 
 #define INSERT_FW_HEADER(var, hdr) \
@@ -1048,25 +1600,31 @@ if (msginfo->var && *msginfo->var) { \
 
 Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
                         gboolean as_attach, const gchar *body,
-                        gboolean no_extedit)
+                        gboolean no_extedit,
+                        gboolean batch)
 {
        Compose *compose;
-       GtkSText *text;
+       GtkTextView *textview;
+       GtkTextBuffer *textbuf;
+       GtkTextIter iter;
 
-       g_return_val_if_fail(msginfo != NULL, NULL);
-       g_return_val_if_fail(msginfo->folder != NULL, NULL);
+       cm_return_val_if_fail(msginfo != NULL, NULL);
+       cm_return_val_if_fail(msginfo->folder != NULL, NULL);
 
        if (!account && 
            !(account = compose_guess_forward_account_from_msginfo
                                (msginfo)))
                account = cur_account;
 
-       compose = compose_create(account, COMPOSE_FORWARD);
+       compose = compose_create(account, msginfo->folder, COMPOSE_FORWARD, batch);
 
+       compose->updating = TRUE;
        compose->fwdinfo = procmsg_msginfo_get_full_info(msginfo);
        if (!compose->fwdinfo)
                compose->fwdinfo = procmsg_msginfo_copy(msginfo);
 
+       compose_extract_original_charset(compose);
+
        if (msginfo->subject && *msginfo->subject) {
                gchar *buf, *buf2, *p;
 
@@ -1081,13 +1639,54 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
                g_free(buf2);
        }
 
-       text = GTK_STEXT(compose->text);
-       gtk_stext_freeze(text);
+       /* override from name according to folder properties */
+       if (msginfo->folder && msginfo->folder->prefs &&
+               msginfo->folder->prefs->forward_with_format &&
+               msginfo->folder->prefs->forward_override_from_format &&
+               *msginfo->folder->prefs->forward_override_from_format != '\0') {
+
+               gchar *tmp = NULL;
+               gchar *buf = NULL;
+               MsgInfo *full_msginfo = NULL;
+
+               if (!as_attach)
+                       full_msginfo = procmsg_msginfo_get_full_info(msginfo);
+               if (!full_msginfo)
+                       full_msginfo = procmsg_msginfo_copy(msginfo);
+
+               /* decode \-escape sequences in the internal representation of the quote format */
+               tmp = malloc(strlen(msginfo->folder->prefs->forward_override_from_format)+1);
+               pref_get_unescaped_pref(tmp, msginfo->folder->prefs->forward_override_from_format);
+
+#ifdef USE_ENCHANT
+               quote_fmt_init(full_msginfo, NULL, NULL, FALSE, compose->account, FALSE,
+                               compose->gtkaspell);
+#else
+               quote_fmt_init(full_msginfo, NULL, NULL, FALSE, compose->account, FALSE);
+#endif
+               quote_fmt_scan_string(tmp);
+               quote_fmt_parse();
+
+               buf = quote_fmt_get_buffer();
+               if (buf == NULL)
+                       alertpanel_error(_("Message forward From format error."));
+               else
+                       gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
+               quote_fmt_reset_vartable();
+
+               g_free(tmp);
+               procmsg_msginfo_free(full_msginfo);
+       }
 
+       textview = GTK_TEXT_VIEW(compose->text);
+       textbuf = gtk_text_view_get_buffer(textview);
+       compose_create_tags(textview, compose);
+       
+       undo_block(compose->undostruct);
        if (as_attach) {
                gchar *msgfile;
 
-               msgfile = procmsg_get_message_file_path(msginfo);
+               msgfile = procmsg_get_message_file(msginfo);
                if (!is_file_exist(msgfile))
                        g_warning("%s: file not exist\n", msgfile);
                else
@@ -1096,43 +1695,65 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
 
                g_free(msgfile);
        } else {
-               gchar *qmark;
+               const gchar *qmark = NULL;
+               const gchar *body_fmt = NULL;
                MsgInfo *full_msginfo;
 
+               if (prefs_common.fw_quotefmt && *prefs_common.fw_quotefmt)
+                       body_fmt = gettext(prefs_common.fw_quotefmt);
+               else
+                       body_fmt = "";
+       
                full_msginfo = procmsg_msginfo_get_full_info(msginfo);
                if (!full_msginfo)
                        full_msginfo = procmsg_msginfo_copy(msginfo);
 
-               if (prefs_common.fw_quotemark &&
-                   *prefs_common.fw_quotemark)
+               /* use the forward format of folder (if enabled), or the account's one
+                  (if enabled) or fallback to the global forward format, which is always
+                  enabled (even if empty), and use the relevant quotemark */
+               if (msginfo->folder && msginfo->folder->prefs &&
+                               msginfo->folder->prefs->forward_with_format) {
+                       qmark = msginfo->folder->prefs->forward_quotemark;
+                       body_fmt = msginfo->folder->prefs->forward_body_format;
+
+               } else if (account->forward_with_format) {
+                       qmark = account->forward_quotemark;
+                       body_fmt = account->forward_body_format;
+
+               } else {
                        qmark = prefs_common.fw_quotemark;
-               else
+                       if (prefs_common.fw_quotefmt && *prefs_common.fw_quotefmt)
+                               body_fmt = gettext(prefs_common.fw_quotefmt);
+                       else
+                               body_fmt = "";
+               }
+
+               /* empty quotemark is not allowed */
+               if (qmark == NULL || *qmark == '\0')
                        qmark = "> ";
 
                compose_quote_fmt(compose, full_msginfo,
-                                 prefs_common.fw_quotefmt,
-                                 qmark, body);
+                                 body_fmt, qmark, body, FALSE, TRUE,
+                                         _("Message forward format error at line %d."));
+               compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
+               quote_fmt_reset_vartable();
                compose_attach_parts(compose, msginfo);
 
                procmsg_msginfo_free(full_msginfo);
        }
 
+       SIGNAL_BLOCK(textbuf);
+
        if (account->auto_sig)
                compose_insert_sig(compose, FALSE);
 
-       if (prefs_common.linewrap_quote)
-               compose_wrap_line_all(compose);
+       compose_wrap_all(compose);
 
-       gtk_editable_set_position(GTK_EDITABLE(compose->text), 0);
-       gtk_stext_set_point(GTK_STEXT(compose->text), 0);
+       SIGNAL_UNBLOCK(textbuf);
+       
+       gtk_text_buffer_get_start_iter(textbuf, &iter);
+       gtk_text_buffer_place_cursor(textbuf, &iter);
 
-       gtk_stext_thaw(text);
-#if 0 /* NEW COMPOSE GUI */
-       if (account->protocol != A_NNTP)
-               gtk_widget_grab_focus(compose->to_entry);
-       else
-               gtk_widget_grab_focus(compose->newsgroups_entry);
-#endif
        gtk_widget_grab_focus(compose->header_last->entry);
 
        if (!no_extedit && prefs_common.auto_exteditor)
@@ -1144,23 +1765,43 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
 
                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);
+               compose_set_save_to(compose, folderidentifier);
                g_free(folderidentifier);
        }
 
+       undo_unblock(compose->undostruct);
+       
+       compose->modified = FALSE;
+       compose_set_title(compose);
+
+       compose->updating = FALSE;
+       compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
+       SCROLL_TO_CURSOR(compose);
+
+       if (compose->deferred_destroy) {
+               compose_destroy(compose);
+               return NULL;
+       }
+
         return compose;
 }
 
 #undef INSERT_FW_HEADER
 
-Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
+static Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
 {
        Compose *compose;
-       GtkSText *text;
+       GtkTextView *textview;
+       GtkTextBuffer *textbuf;
+       GtkTextIter iter;
        GSList *msginfo;
        gchar *msgfile;
+       gboolean single_mail = TRUE;
+       
+       cm_return_val_if_fail(msginfo_list != NULL, NULL);
 
-       g_return_val_if_fail(msginfo_list != NULL, NULL);
+       if (g_slist_length(msginfo_list) > 1)
+               single_mail = FALSE;
 
        for (msginfo = msginfo_list; msginfo != NULL; msginfo = msginfo->next)
                if (((MsgInfo *)msginfo->data)->folder == NULL)
@@ -1172,20 +1813,68 @@ Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
                                (msginfo_list->data)))
                account = cur_account;
 
-       g_return_val_if_fail(account != NULL, NULL);
+       cm_return_val_if_fail(account != NULL, NULL);
 
        for (msginfo = msginfo_list; msginfo != NULL; msginfo = msginfo->next) {
-               MSG_UNSET_PERM_FLAGS(((MsgInfo *)msginfo->data)->flags, MSG_REPLIED);
-               MSG_SET_PERM_FLAGS(((MsgInfo *)msginfo->data)->flags, MSG_FORWARDED);
+               if (msginfo->data) {
+                       MSG_UNSET_PERM_FLAGS(((MsgInfo *)msginfo->data)->flags, MSG_REPLIED);
+                       MSG_SET_PERM_FLAGS(((MsgInfo *)msginfo->data)->flags, MSG_FORWARDED);
+               }
+       }
+
+       if (msginfo_list == NULL || msginfo_list->data == NULL) {
+               g_warning("no msginfo_list");
+               return NULL;
        }
 
-       compose = compose_create(account, COMPOSE_FORWARD);
+       compose = compose_create(account, ((MsgInfo *)msginfo_list->data)->folder, COMPOSE_FORWARD, FALSE);
 
-       text = GTK_STEXT(compose->text);
-       gtk_stext_freeze(text);
-               
+       compose->updating = TRUE;
+
+       /* override from name according to folder properties */
+       if (msginfo_list->data) {
+               MsgInfo *msginfo = msginfo_list->data;
+
+               if (msginfo->folder && msginfo->folder->prefs &&
+                       msginfo->folder->prefs->forward_with_format &&
+                       msginfo->folder->prefs->forward_override_from_format &&
+                       *msginfo->folder->prefs->forward_override_from_format != '\0') {
+
+                       gchar *tmp = NULL;
+                       gchar *buf = NULL;
+
+                       /* decode \-escape sequences in the internal representation of the quote format */
+                       tmp = malloc(strlen(msginfo->folder->prefs->forward_override_from_format)+1);
+                       pref_get_unescaped_pref(tmp, msginfo->folder->prefs->forward_override_from_format);
+
+#ifdef USE_ENCHANT
+                       quote_fmt_init(msginfo, NULL, NULL, FALSE, compose->account, FALSE,
+                                       compose->gtkaspell);
+#else
+                       quote_fmt_init(msginfo, NULL, NULL, FALSE, compose->account, FALSE);
+#endif
+                       quote_fmt_scan_string(tmp);
+                       quote_fmt_parse();
+
+                       buf = quote_fmt_get_buffer();
+                       if (buf == NULL)
+                               alertpanel_error(_("Message forward From format error."));
+                       else
+                               gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
+                       quote_fmt_reset_vartable();
+
+                       g_free(tmp);
+               }
+       }
+
+       textview = GTK_TEXT_VIEW(compose->text);
+       textbuf = gtk_text_view_get_buffer(textview);
+       compose_create_tags(textview, compose);
+       
+       undo_block(compose->undostruct);
        for (msginfo = msginfo_list; msginfo != NULL; msginfo = msginfo->next) {
-               msgfile = procmsg_get_message_file_path((MsgInfo *)msginfo->data);
+               msgfile = procmsg_get_message_file((MsgInfo *)msginfo->data);
+
                if (!is_file_exist(msgfile))
                        g_warning("%s: file not exist\n", msgfile);
                else
@@ -1193,51 +1882,169 @@ Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
                                "message/rfc822");
                g_free(msgfile);
        }
+       
+       if (single_mail) {
+               MsgInfo *info = (MsgInfo *)msginfo_list->data;
+               if (info->subject && *info->subject) {
+                       gchar *buf, *buf2, *p;
+
+                       buf = p = g_strdup(info->subject);
+                       p += subject_get_prefix_length(p);
+                       memmove(buf, p, strlen(p) + 1);
+
+                       buf2 = g_strdup_printf("Fw: %s", buf);
+                       gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf2);
+
+                       g_free(buf);
+                       g_free(buf2);
+               }
+       } else {
+               gtk_entry_set_text(GTK_ENTRY(compose->subject_entry),
+                       _("Fw: multiple emails"));
+       }
 
+       SIGNAL_BLOCK(textbuf);
+       
        if (account->auto_sig)
                compose_insert_sig(compose, FALSE);
 
-       if (prefs_common.linewrap_quote)
-               compose_wrap_line_all(compose);
+       compose_wrap_all(compose);
 
-       gtk_editable_set_position(GTK_EDITABLE(compose->text), 0);
-       gtk_stext_set_point(GTK_STEXT(compose->text), 0);
+       SIGNAL_UNBLOCK(textbuf);
+       
+       gtk_text_buffer_get_start_iter(textbuf, &iter);
+       gtk_text_buffer_place_cursor(textbuf, &iter);
 
-       gtk_stext_thaw(text);
        gtk_widget_grab_focus(compose->header_last->entry);
-       
-#if 0 /* NEW COMPOSE GUI */
-       if (account->protocol != A_NNTP)
-               gtk_widget_grab_focus(compose->to_entry);
-       else
-               gtk_widget_grab_focus(compose->newsgroups_entry);
-#endif
+       undo_unblock(compose->undostruct);
+       compose->modified = FALSE;
+       compose_set_title(compose);
+
+       compose->updating = FALSE;
+       compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
+       SCROLL_TO_CURSOR(compose);
+
+       if (compose->deferred_destroy) {
+               compose_destroy(compose);
+               return NULL;
+       }
 
        return compose;
 }
 
-void compose_reedit(MsgInfo *msginfo)
+static gboolean compose_is_sig_separator(Compose *compose, GtkTextBuffer *textbuf, GtkTextIter *iter) 
 {
-       Compose *compose;
+       GtkTextIter start = *iter;
+       GtkTextIter end_iter;
+       int start_pos = gtk_text_iter_get_offset(&start);
+       gchar *str = NULL;
+       if (!compose->account->sig_sep)
+               return FALSE;
+       
+       gtk_text_buffer_get_iter_at_offset(textbuf, &end_iter,
+               start_pos+strlen(compose->account->sig_sep));
+
+       /* check sig separator */
+       str = gtk_text_iter_get_text(&start, &end_iter);
+       if (!strcmp(str, compose->account->sig_sep)) {
+               gchar *tmp = NULL;
+               /* check end of line (\n) */
+               gtk_text_buffer_get_iter_at_offset(textbuf, &start,
+                       start_pos+strlen(compose->account->sig_sep));
+               gtk_text_buffer_get_iter_at_offset(textbuf, &end_iter,
+                       start_pos+strlen(compose->account->sig_sep)+1);
+               tmp = gtk_text_iter_get_text(&start, &end_iter);
+               if (!strcmp(tmp,"\n")) {
+                       g_free(str);
+                       g_free(tmp);
+                       return TRUE;
+               }
+               g_free(tmp);    
+       }
+       g_free(str);
+
+       return FALSE;
+}
+
+static void compose_colorize_signature(Compose *compose)
+{
+       GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(compose->text));
+       GtkTextIter iter;
+       GtkTextIter end_iter;
+       gtk_text_buffer_get_start_iter(buffer, &iter);
+       while (gtk_text_iter_forward_line(&iter))
+               if (compose_is_sig_separator(compose, buffer, &iter)) {
+                       gtk_text_buffer_get_end_iter(buffer, &end_iter);
+                       gtk_text_buffer_apply_tag_by_name(buffer,"signature",&iter, &end_iter);
+               }
+}
+
+#define BLOCK_WRAP() {                                                 \
+       prev_autowrap = compose->autowrap;                              \
+       buffer = gtk_text_view_get_buffer(                              \
+                                       GTK_TEXT_VIEW(compose->text));  \
+       compose->autowrap = FALSE;                                      \
+                                                                       \
+       g_signal_handlers_block_by_func(G_OBJECT(buffer),               \
+                               G_CALLBACK(compose_changed_cb),         \
+                               compose);                               \
+       g_signal_handlers_block_by_func(G_OBJECT(buffer),               \
+                               G_CALLBACK(text_inserted),              \
+                               compose);                               \
+}
+#define UNBLOCK_WRAP() {                                               \
+       compose->autowrap = prev_autowrap;                              \
+       if (compose->autowrap) {                                        \
+               gint old = compose->draft_timeout_tag;                  \
+               compose->draft_timeout_tag = -2;                        \
+               compose_wrap_all(compose);                              \
+               compose->draft_timeout_tag = old;                       \
+       }                                                               \
+                                                                       \
+       g_signal_handlers_unblock_by_func(G_OBJECT(buffer),             \
+                               G_CALLBACK(compose_changed_cb),         \
+                               compose);                               \
+       g_signal_handlers_unblock_by_func(G_OBJECT(buffer),             \
+                               G_CALLBACK(text_inserted),              \
+                               compose);                               \
+}
+
+Compose *compose_reedit(MsgInfo *msginfo, gboolean batch)
+{
+       Compose *compose = NULL;
        PrefsAccount *account = NULL;
-       GtkSText *text;
+       GtkTextView *textview;
+       GtkTextBuffer *textbuf;
+       GtkTextMark *mark;
+       GtkTextIter iter;
        FILE *fp;
        gchar buf[BUFFSIZE];
        gboolean use_signing = FALSE;
        gboolean use_encryption = FALSE;
        gchar *privacy_system = NULL;
+       int priority = PRIORITY_NORMAL;
+       MsgInfo *replyinfo = NULL, *fwdinfo = NULL;
+       gboolean autowrap = prefs_common.autowrap;
+       gboolean autoindent = prefs_common.auto_indent;
 
-       g_return_if_fail(msginfo != NULL);
-       g_return_if_fail(msginfo->folder != NULL);
+       cm_return_val_if_fail(msginfo != NULL, NULL);
+       cm_return_val_if_fail(msginfo->folder != NULL, NULL);
 
-       if (compose_put_existing_to_front(msginfo)) 
-               return;
+       if (compose_put_existing_to_front(msginfo)) {
+               return NULL;
+       }
 
-        if (msginfo->folder->stype == F_QUEUE || msginfo->folder->stype == F_DRAFT) {
+        if (folder_has_parent_of_type(msginfo->folder, F_QUEUE) ||
+           folder_has_parent_of_type(msginfo->folder, F_DRAFT)) {
                gchar queueheader_buf[BUFFSIZE];
                gint id, param;
 
                /* Select Account from queue headers */
+               if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
+                                            sizeof(queueheader_buf), "X-Claws-Account-Id:")) {
+                       id = atoi(&queueheader_buf[strlen("X-Claws-Account-Id:")]);
+                       account = account_find_from_id(id);
+               }
                if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
                                             sizeof(queueheader_buf), "X-Sylpheed-Account-Id:")) {
                        id = atoi(&queueheader_buf[strlen("X-Sylpheed-Account-Id:")]);
@@ -1255,7 +2062,13 @@ void compose_reedit(MsgInfo *msginfo)
                }
                if (!account && !procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
                                                                sizeof(queueheader_buf), "S:")) {
-                       account = account_find_from_address(queueheader_buf);
+                       account = account_find_from_address(queueheader_buf, FALSE);
+               }
+               if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
+                                            sizeof(queueheader_buf), "X-Claws-Sign:")) {
+                       param = atoi(&queueheader_buf[strlen("X-Claws-Sign:")]);
+                       use_signing = param;
+                       
                }
                if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
                                             sizeof(queueheader_buf), "X-Sylpheed-Sign:")) {
@@ -1263,11 +2076,30 @@ void compose_reedit(MsgInfo *msginfo)
                        use_signing = param;
                        
                }
+               if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
+                                            sizeof(queueheader_buf), "X-Claws-Encrypt:")) {
+                       param = atoi(&queueheader_buf[strlen("X-Claws-Encrypt:")]);
+                       use_encryption = param;
+               }
                if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
                                             sizeof(queueheader_buf), "X-Sylpheed-Encrypt:")) {
                        param = atoi(&queueheader_buf[strlen("X-Sylpheed-Encrypt:")]);
                        use_encryption = param;
                }
+               if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
+                                            sizeof(queueheader_buf), "X-Claws-Auto-Wrapping:")) {
+                       param = atoi(&queueheader_buf[strlen("X-Claws-Auto-Wrapping:")]);
+                       autowrap = param;
+               }
+               if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
+                                            sizeof(queueheader_buf), "X-Claws-Auto-Indent:")) {
+                       param = atoi(&queueheader_buf[strlen("X-Claws-Auto-Indent:")]);
+                       autoindent = param;
+               }
+                if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
+                                            sizeof(queueheader_buf), "X-Claws-Privacy-System:")) {
+                        privacy_system = g_strdup(&queueheader_buf[strlen("X-Claws-Privacy-System:")]);
+                }
                 if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
                                             sizeof(queueheader_buf), "X-Sylpheed-Privacy-System:")) {
                         privacy_system = g_strdup(&queueheader_buf[strlen("X-Sylpheed-Privacy-System:")]);
@@ -1275,82 +2107,178 @@ void compose_reedit(MsgInfo *msginfo)
                if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
                                             sizeof(queueheader_buf), "X-Priority: ")) {
                        param = atoi(&queueheader_buf[strlen("X-Priority: ")]); /* mind the space */
-                       compose->priority = param;
+                       priority = param;
+               }
+               if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
+                                            sizeof(queueheader_buf), "RMID:")) {
+                       gchar **tokens = g_strsplit(&queueheader_buf[strlen("RMID:")], "\t", 0);
+                       if (tokens[0] && tokens[1] && tokens[2]) {
+                               FolderItem *orig_item = folder_find_item_from_identifier(tokens[0]);
+                               if (orig_item != NULL) {
+                                       replyinfo = folder_item_get_msginfo_by_msgid(orig_item, tokens[2]);
+                               }
+                       }
+                       g_strfreev(tokens);
+               }
+               if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, 
+                                            sizeof(queueheader_buf), "FMID:")) {
+                       gchar **tokens = g_strsplit(&queueheader_buf[strlen("FMID:")], "\t", 0);
+                       if (tokens[0] && tokens[1] && tokens[2]) {
+                               FolderItem *orig_item = folder_find_item_from_identifier(tokens[0]);
+                               if (orig_item != NULL) {
+                                       fwdinfo = folder_item_get_msginfo_by_msgid(orig_item, tokens[2]);
+                               }
+                       }
+                       g_strfreev(tokens);
                }
-       } else 
+       } else {
                account = msginfo->folder->folder->account;
+       }
 
        if (!account && prefs_common.reedit_account_autosel) {
                        gchar from[BUFFSIZE];
-               if (!procheader_get_header_from_msginfo(msginfo, from, sizeof(from), "FROM:")){
+               if (!procheader_get_header_from_msginfo(msginfo, from, sizeof(from), "FROM:")) {
                        extract_address(from);
-                       account = account_find_from_address(from);
+                       account = account_find_from_address(from, FALSE);
                 }
        }
-        if (!account) account = cur_account;
-       g_return_if_fail(account != NULL);
+        if (!account) {
+               account = cur_account;
+        }
+       cm_return_val_if_fail(account != NULL, NULL);
+
+       compose = compose_create(account, msginfo->folder, COMPOSE_REEDIT, batch);
+
+       cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Edit/AutoWrap", autowrap);
+       cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Edit/AutoIndent", autoindent);
+       compose->autowrap = autowrap;
+       compose->replyinfo = replyinfo;
+       compose->fwdinfo = fwdinfo;
+
+       compose->updating = TRUE;
+       compose->priority = priority;
+
+       if (privacy_system != NULL) {
+               compose->privacy_system = privacy_system;
+               compose_use_signing(compose, use_signing);
+               compose_use_encryption(compose, use_encryption);
+               compose_update_privacy_system_menu_item(compose, FALSE);
+       } else {
+               activate_privacy_system(compose, account, FALSE);
+       }
 
-       compose = compose_create(account, COMPOSE_REEDIT);
-       compose->privacy_system = privacy_system;
-       compose_use_signing(compose, use_signing);
-       compose_use_encryption(compose, use_encryption);
        compose->targetinfo = procmsg_msginfo_copy(msginfo);
 
-        if (msginfo->folder->stype == F_QUEUE
-       ||  msginfo->folder->stype == F_DRAFT) {
+       compose_extract_original_charset(compose);
+
+        if (folder_has_parent_of_type(msginfo->folder, F_QUEUE) ||
+           folder_has_parent_of_type(msginfo->folder, F_DRAFT)) {
                gchar queueheader_buf[BUFFSIZE];
 
                /* Set message save folder */
                if (!procheader_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);
+                       compose_set_save_to(compose, &queueheader_buf[4]);
+               }
+               if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, sizeof(queueheader_buf), "RRCPT:")) {
+                       gint active = atoi(&queueheader_buf[strlen("RRCPT:")]);
+                       if (active) {
+                               cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/RequestRetRcpt", TRUE);
+                       }
                }
        }
        
-       if (compose_parse_header(compose, msginfo) < 0) return;
+       if (compose_parse_header(compose, msginfo) < 0) {
+               compose->updating = FALSE;
+               compose_destroy(compose);
+               return NULL;
+       }
        compose_reedit_set_entry(compose, msginfo);
 
-       text = GTK_STEXT(compose->text);
-       gtk_stext_freeze(text);
+       textview = GTK_TEXT_VIEW(compose->text);
+       textbuf = gtk_text_view_get_buffer(textview);
+       compose_create_tags(textview, compose);
+
+       mark = gtk_text_buffer_get_insert(textbuf);
+       gtk_text_buffer_get_iter_at_mark(textbuf, &iter, mark);
 
-       if ((fp = procmime_get_first_text_content(msginfo)) == NULL)
+       g_signal_handlers_block_by_func(G_OBJECT(textbuf),
+                                       G_CALLBACK(compose_changed_cb),
+                                       compose);
+       
+       if (MSG_IS_ENCRYPTED(msginfo->flags)) {
+               fp = procmime_get_first_encrypted_text_content(msginfo);
+               if (fp) {
+                       compose_force_encryption(compose, account, TRUE, NULL);
+               }
+       } else {
+               fp = procmime_get_first_text_content(msginfo);
+       }
+       if (fp == NULL) {
                g_warning("Can't get text part\n");
-       else {
+       }
+
+       if (fp != NULL) {
+               gboolean prev_autowrap = compose->autowrap;
+               GtkTextBuffer *buffer = textbuf;
+               BLOCK_WRAP();
                while (fgets(buf, sizeof(buf), fp) != NULL) {
                        strcrchomp(buf);
-                       gtk_stext_insert(text, NULL, NULL, NULL, buf, -1);
+                       gtk_text_buffer_insert(textbuf, &iter, buf, -1);
                }
+               UNBLOCK_WRAP();
                fclose(fp);
        }
+       
        compose_attach_parts(compose, msginfo);
 
-       gtk_stext_thaw(text);
+       compose_colorize_signature(compose);
+
+       g_signal_handlers_unblock_by_func(G_OBJECT(textbuf),
+                                       G_CALLBACK(compose_changed_cb),
+                                       compose);
+
        gtk_widget_grab_focus(compose->text);
 
-        if (prefs_common.auto_exteditor)
+        if (prefs_common.auto_exteditor) {
                compose_exec_ext_editor(compose);
+       }
+       compose->modified = FALSE;
+       compose_set_title(compose);
+
+       compose->updating = FALSE;
+       compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
+       SCROLL_TO_CURSOR(compose);
+
+       if (compose->deferred_destroy) {
+               compose_destroy(compose);
+               return NULL;
+       }
+       
+       compose->sig_str = account_get_signature_str(compose->account);
+       
+       return compose;
 }
 
-Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo)
+Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo,
+                                                gboolean batch)
 {
        Compose *compose;
        gchar *filename;
-       GtkItemFactory *ifactory;
        FolderItem *item;
 
-       g_return_val_if_fail(msginfo != NULL, NULL);
+       cm_return_val_if_fail(msginfo != NULL, NULL);
 
        if (!account)
                account = account_get_reply_account(msginfo,
                                        prefs_common.reply_account_autosel);
-       g_return_val_if_fail(account != NULL, NULL);
+       cm_return_val_if_fail(account != NULL, NULL);
 
-       compose = compose_create(account, COMPOSE_REDIRECT);
-       ifactory = gtk_item_factory_from_widget(compose->menubar);
+       compose = compose_create(account, msginfo->folder, COMPOSE_REDIRECT, batch);
 
+       compose->updating = TRUE;
+
+       compose_create_tags(GTK_TEXT_VIEW(compose->text), compose);
        compose->replyinfo = NULL;
        compose->fwdinfo = NULL;
 
@@ -1358,9 +2286,14 @@ Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo)
 
        gtk_widget_grab_focus(compose->header_last->entry);
 
-       filename = procmsg_get_message_file_path(msginfo);
-       if (filename == NULL)
+       filename = procmsg_get_message_file(msginfo);
+
+       if (filename == NULL) {
+               compose->updating = FALSE;
+               compose_destroy(compose);
+
                return NULL;
+       }
 
        compose->redirect_filename = filename;
        
@@ -1371,7 +2304,7 @@ Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo)
 
                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);
+               compose_set_save_to(compose, folderidentifier);
                g_free(folderidentifier);
        }
 
@@ -1382,35 +2315,54 @@ Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo)
                                   msginfo->subject);
        gtk_editable_set_editable(GTK_EDITABLE(compose->subject_entry), FALSE);
 
-       gtk_stext_freeze(GTK_STEXT(compose->text));
-       compose_quote_fmt(compose, msginfo, "%M", NULL, NULL);
-       gtk_editable_set_editable(GTK_EDITABLE(compose->text), FALSE);
-       gtk_stext_thaw(GTK_STEXT(compose->text));
-
-       ifactory = gtk_item_factory_from_widget(compose->popupmenu);
-       menu_set_sensitive(ifactory, "/Add...", FALSE);
-       menu_set_sensitive(ifactory, "/Remove", FALSE);
-       menu_set_sensitive(ifactory, "/Properties...", FALSE);
-
-       ifactory = gtk_item_factory_from_widget(compose->menubar);
-       menu_set_sensitive(ifactory, "/Message/Save", FALSE);
-       menu_set_sensitive(ifactory, "/Message/Insert file", FALSE);
-       menu_set_sensitive(ifactory, "/Message/Attach file", FALSE);
-       menu_set_sensitive(ifactory, "/Message/Insert signature", FALSE);
-       menu_set_sensitive(ifactory, "/Edit", FALSE);
-       menu_set_sensitive(ifactory, "/Options", FALSE);
-       menu_set_sensitive(ifactory, "/Tools/Show ruler", FALSE);
-       menu_set_sensitive(ifactory, "/Tools/Actions", FALSE);
+       compose_quote_fmt(compose, msginfo, "%M", NULL, NULL, FALSE, FALSE,
+                                         _("Message redirect format error at line %d."));
+       quote_fmt_reset_vartable();
+       gtk_text_view_set_editable(GTK_TEXT_VIEW(compose->text), FALSE);
+
+       compose_colorize_signature(compose);
+
        
-       gtk_widget_set_sensitive(compose->toolbar->draft_btn, FALSE);
-       gtk_widget_set_sensitive(compose->toolbar->insert_btn, FALSE);
-       gtk_widget_set_sensitive(compose->toolbar->attach_btn, FALSE);
-       gtk_widget_set_sensitive(compose->toolbar->sig_btn, FALSE);
-       gtk_widget_set_sensitive(compose->toolbar->exteditor_btn, FALSE);
-       gtk_widget_set_sensitive(compose->toolbar->linewrap_current_btn, FALSE);
-       gtk_widget_set_sensitive(compose->toolbar->linewrap_all_btn, FALSE);
+       cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Add", FALSE);
+       cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Remove", FALSE);
+       cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Properties", FALSE);
+
+       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/Save", FALSE);
+       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertFile", FALSE);
+       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/AttachFile", FALSE);
+       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertSig", FALSE);
+       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit", FALSE);
+       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options", FALSE);
+       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Tools/ShowRuler", FALSE);
+       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Tools/Actions", FALSE);
+       
+       if (compose->toolbar->draft_btn)
+               gtk_widget_set_sensitive(compose->toolbar->draft_btn, FALSE);
+       if (compose->toolbar->insert_btn)
+               gtk_widget_set_sensitive(compose->toolbar->insert_btn, FALSE);
+       if (compose->toolbar->attach_btn)
+               gtk_widget_set_sensitive(compose->toolbar->attach_btn, FALSE);
+       if (compose->toolbar->sig_btn)
+               gtk_widget_set_sensitive(compose->toolbar->sig_btn, FALSE);
+       if (compose->toolbar->exteditor_btn)
+               gtk_widget_set_sensitive(compose->toolbar->exteditor_btn, FALSE);
+       if (compose->toolbar->linewrap_current_btn)
+               gtk_widget_set_sensitive(compose->toolbar->linewrap_current_btn, FALSE);
+       if (compose->toolbar->linewrap_all_btn)
+               gtk_widget_set_sensitive(compose->toolbar->linewrap_all_btn, FALSE);
 
-        return compose;
+       compose->modified = FALSE;
+       compose_set_title(compose);
+       compose->updating = FALSE;
+       compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
+       SCROLL_TO_CURSOR(compose);
+
+       if (compose->deferred_destroy) {
+               compose_destroy(compose);
+               return NULL;
+       }
+       
+       return compose;
 }
 
 GList *compose_get_compose_list(void)
@@ -1421,33 +2373,11 @@ GList *compose_get_compose_list(void)
 void compose_entry_append(Compose *compose, const gchar *address,
                          ComposeEntryType type)
 {
-       gchar *header;
-
+       const gchar *header;
+       gchar *cur, *begin;
+       gboolean in_quote = FALSE;
        if (!address || *address == '\0') return;
 
-#if 0 /* NEW COMPOSE GUI */
-       switch (type) {
-       case COMPOSE_CC:
-               entry = GTK_ENTRY(compose->cc_entry);
-               break;
-       case COMPOSE_BCC:
-               entry = GTK_ENTRY(compose->bcc_entry);
-               break;
-       case COMPOSE_NEWSGROUPS:
-               entry = GTK_ENTRY(compose->newsgroups_entry);
-               break;
-       case COMPOSE_TO:
-       default:
-               entry = GTK_ENTRY(compose->to_entry);
-               break;
-       }
-
-       text = gtk_entry_get_text(entry);
-       if (*text != '\0')
-               gtk_entry_append_text(entry, ", ");
-       gtk_entry_append_text(entry, address);
-#endif
-
        switch (type) {
        case COMPOSE_CC:
                header = N_("Cc:");
@@ -1469,37 +2399,71 @@ void compose_entry_append(Compose *compose, const gchar *address,
                header = N_("To:");
                break;
        }
-       header = prefs_common.trans_hdr ? gettext(header) : header;
-
-       compose_add_header_entry(compose, header, (gchar *)address);
+       header = prefs_common_translated_header_name(header);
+       
+       cur = begin = (gchar *)address;
+       
+       /* we separate the line by commas, but not if we're inside a quoted
+        * string */
+       while (*cur != '\0') {
+               if (*cur == '"') 
+                       in_quote = !in_quote;
+               if (*cur == ',' && !in_quote) {
+                       gchar *tmp = g_strdup(begin);
+                       gchar *o_tmp = tmp;
+                       tmp[cur-begin]='\0';
+                       cur++;
+                       begin = cur;
+                       while (*tmp == ' ' || *tmp == '\t')
+                               tmp++;
+                       compose_add_header_entry(compose, header, tmp);
+                       g_free(o_tmp);
+                       continue;
+               }
+               cur++;
+       }
+       if (begin < cur) {
+               gchar *tmp = g_strdup(begin);
+               gchar *o_tmp = tmp;
+               tmp[cur-begin]='\0';
+               cur++;
+               begin = cur;
+               while (*tmp == ' ' || *tmp == '\t')
+                       tmp++;
+               compose_add_header_entry(compose, header, tmp);
+               g_free(o_tmp);          
+       }
 }
 
-void compose_entry_mark_default_to(Compose *compose, const gchar *mailto)
+static void compose_entry_mark_default_to(Compose *compose, const gchar *mailto)
 {
-       static GtkStyle *bold_style = NULL;
-       static GdkColor bold_color;
-       static GdkFont *bold_font = NULL;
+       static GdkColor yellow;
+       static GdkColor black;
+       static gboolean yellow_initialised = FALSE;
        GSList *h_list;
        GtkEntry *entry;
                
+       if (!yellow_initialised) {
+               gdk_color_parse("#f5f6be", &yellow);
+               gdk_color_parse("#000000", &black);
+               yellow_initialised = gdk_colormap_alloc_color(
+                       gdk_colormap_get_system(), &yellow, FALSE, TRUE);
+               yellow_initialised &= gdk_colormap_alloc_color(
+                       gdk_colormap_get_system(), &black, FALSE, TRUE);
+       }
+
        for (h_list = compose->header_list; h_list != NULL; h_list = h_list->next) {
                entry = GTK_ENTRY(((ComposeHeaderEntry *)h_list->data)->entry);
                if (gtk_entry_get_text(entry) && 
-                   !g_strcasecmp(gtk_entry_get_text(entry), mailto)) {
-                       gtk_widget_ensure_style(GTK_WIDGET(entry));
-                       if (!bold_style) {
-                               gtkut_convert_int_to_gdk_color
-                                       (prefs_common.color_new, &bold_color);
-                               bold_style = gtk_style_copy(gtk_widget_get_style
-                                       (GTK_WIDGET(entry)));
-                               if (!bold_font)
-                                       bold_font = gtkut_font_load
-                                               (prefs_common.boldfont);
-                               if (bold_font)
-                                       bold_style->font = bold_font;
-                               bold_style->fg[GTK_STATE_NORMAL] = bold_color;
+                   !g_utf8_collate(gtk_entry_get_text(entry), mailto)) {
+                       if (yellow_initialised) {
+                               gtk_widget_modify_base(
+                                       GTK_WIDGET(((ComposeHeaderEntry *)h_list->data)->entry),
+                                       GTK_STATE_NORMAL, &yellow);
+                               gtk_widget_modify_text(
+                                       GTK_WIDGET(((ComposeHeaderEntry *)h_list->data)->entry),
+                                       GTK_STATE_NORMAL, &black);
                        }
-                       gtk_widget_set_style(GTK_WIDGET(entry), bold_style);
                }
        }
 }
@@ -1509,42 +2473,42 @@ void compose_toolbar_cb(gint action, gpointer data)
        ToolbarItem *toolbar_item = (ToolbarItem*)data;
        Compose *compose = (Compose*)toolbar_item->parent;
        
-       g_return_if_fail(compose != NULL);
+       cm_return_if_fail(compose != NULL);
 
        switch(action) {
        case A_SEND:
-               compose_send_cb(compose, 0, NULL);
+               compose_send_cb(NULL, compose);
                break;
        case A_SENDL:
-               compose_send_later_cb(compose, 0, NULL);
+               compose_send_later_cb(NULL, compose);
                break;
        case A_DRAFT:
-               compose_draft_cb(compose, COMPOSE_QUIT_EDITING, NULL);
+               compose_draft(compose, COMPOSE_QUIT_EDITING);
                break;
        case A_INSERT:
-               compose_insert_file_cb(compose, 0, NULL);
+               compose_insert_file_cb(NULL, compose);
                break;
        case A_ATTACH:
-               compose_attach_cb(compose, 0, NULL);
+               compose_attach_cb(NULL, compose);
                break;
        case A_SIG:
                compose_insert_sig(compose, FALSE);
                break;
        case A_EXTEDITOR:
-               compose_ext_editor_cb(compose, 0, NULL);
+               compose_ext_editor_cb(NULL, compose);
                break;
        case A_LINEWRAP_CURRENT:
-               compose_wrap_line(compose);
+               compose_beautify_paragraph(compose, NULL, TRUE);
                break;
        case A_LINEWRAP_ALL:
-               compose_wrap_line_all(compose);
+               compose_wrap_all_full(compose, TRUE);
                break;
        case A_ADDRBOOK:
-               compose_address_cb(compose, 0, NULL);
+               compose_address_cb(NULL, compose);
                break;
-#ifdef USE_ASPELL
+#ifdef USE_ENCHANT
        case A_CHECK_SPELLING:
-               compose_check_all(compose);
+               compose_check_all(NULL, compose);
                break;
 #endif
        default:
@@ -1552,32 +2516,94 @@ void compose_toolbar_cb(gint action, gpointer data)
        }
 }
 
-static void compose_entries_set(Compose *compose, const gchar *mailto)
+static void compose_entries_set(Compose *compose, const gchar *mailto, ComposeEntryType to_type)
 {
        gchar *to = NULL;
        gchar *cc = NULL;
+       gchar *bcc = NULL;
        gchar *subject = NULL;
        gchar *body = NULL;
+       gchar *temp = NULL;
+       gsize  len = 0;
+       gchar **attach = NULL;
 
-       scan_mailto_url(mailto, &to, &cc, NULL, &subject, &body);
+       /* get mailto parts but skip from */
+       scan_mailto_url(mailto, NULL, &to, &cc, &bcc, &subject, &body, &attach);
 
        if (to)
-               compose_entry_append(compose, to, COMPOSE_TO);
+               compose_entry_append(compose, to, to_type);
        if (cc)
                compose_entry_append(compose, cc, COMPOSE_CC);
-       if (subject)
-               gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), subject);
-       if (body) {
-               gtk_stext_insert(GTK_STEXT(compose->text),
-                               NULL, NULL, NULL, body, -1);
-               gtk_stext_insert(GTK_STEXT(compose->text),
-                               NULL, NULL, NULL, "\n", 1);
+       if (bcc)
+               compose_entry_append(compose, bcc, COMPOSE_BCC);
+       if (subject) {
+               if (!g_utf8_validate (subject, -1, NULL)) {
+                       temp = g_locale_to_utf8 (subject, -1, NULL, &len, NULL);
+                       gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), temp);
+                       g_free(temp);
+               } else {
+                       gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), subject);
+               }
        }
+       if (body) {
+               GtkTextView *text = GTK_TEXT_VIEW(compose->text);
+               GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
+               GtkTextMark *mark;
+               GtkTextIter iter;
+               gboolean prev_autowrap = compose->autowrap;
+
+               compose->autowrap = FALSE;
 
+               mark = gtk_text_buffer_get_insert(buffer);
+               gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
+
+               if (!g_utf8_validate (body, -1, NULL)) {
+                       temp = g_locale_to_utf8 (body, -1, NULL, &len, NULL);
+                       gtk_text_buffer_insert(buffer, &iter, temp, -1);
+                       g_free(temp);
+               } else {
+                       gtk_text_buffer_insert(buffer, &iter, body, -1);
+               }
+               gtk_text_buffer_insert(buffer, &iter, "\n", 1);
+
+               compose->autowrap = prev_autowrap;
+               if (compose->autowrap)
+                       compose_wrap_all(compose);
+       }
+
+       if (attach) {
+               gint i = 0, att = 0;
+               gchar *warn_files = NULL;
+               while (attach[i] != NULL) {
+                       gchar *utf8_filename = conv_filename_to_utf8(attach[i]);
+                       if (utf8_filename) {
+                               if (compose_attach_append(compose, attach[i], utf8_filename, NULL)) {
+                                       gchar *tmp = g_strdup_printf("%s%s\n",
+                                                       warn_files?warn_files:"",
+                                                       utf8_filename);
+                                       g_free(warn_files);
+                                       warn_files = tmp;
+                                       att++;
+                               }
+                               g_free(utf8_filename);
+                       } else {
+                               alertpanel_error(_("Couldn't attach a file (charset conversion failed)."));
+                       }
+                       i++;
+               }
+               if (warn_files) {
+                       alertpanel_notice(ngettext(
+                       "The following file has been attached: \n%s",
+                       "The following files have been attached: \n%s", att), warn_files);
+                       g_free(warn_files);
+               }
+       }
        g_free(to);
        g_free(cc);
+       g_free(bcc);
        g_free(subject);
        g_free(body);
+       g_strfreev(attach);
 }
 
 static gint compose_parse_header(Compose *compose, MsgInfo *msginfo)
@@ -1605,30 +2631,24 @@ static gint compose_parse_header(Compose *compose, MsgInfo *msginfo)
        };
 
        FILE *fp;
-       gchar buf[BUFFSIZE];
 
-       g_return_val_if_fail(msginfo != NULL, -1);
+       cm_return_val_if_fail(msginfo != NULL, -1);
 
        if ((fp = procmsg_open_message(msginfo)) == NULL) return -1;
        procheader_get_header_fields(fp, hentry);
        fclose(fp);
 
        if (hentry[H_REPLY_TO].body != NULL) {
-               conv_unmime_header(buf, sizeof(buf), hentry[H_REPLY_TO].body,
-                                  NULL);
-               compose->replyto = g_strdup(buf);
+               if (hentry[H_REPLY_TO].body[0] != '\0') {
+                       compose->replyto =
+                               conv_unmime_header(hentry[H_REPLY_TO].body,
+                                                  NULL);
+               }
                g_free(hentry[H_REPLY_TO].body);
                hentry[H_REPLY_TO].body = NULL;
-               /* if empty replyto, let sylpheed figure it out, i.e.
-                 * neglect the reply-to header. */
-                if (*(compose->replyto) == 0) {
-                        g_free(compose->replyto);
-                        compose->replyto = NULL;
-                }
        }
        if (hentry[H_CC].body != NULL) {
-               conv_unmime_header(buf, sizeof(buf), hentry[H_CC].body, NULL);
-               compose->cc = g_strdup(buf);
+               compose->cc = conv_unmime_header(hentry[H_CC].body, NULL);
                g_free(hentry[H_CC].body);
                hentry[H_CC].body = NULL;
        }
@@ -1643,11 +2663,9 @@ static gint compose_parse_header(Compose *compose, MsgInfo *msginfo)
                hentry[H_REFERENCES].body = NULL;
        }
        if (hentry[H_BCC].body != NULL) {
-               if (compose->mode == COMPOSE_REEDIT) {
-                       conv_unmime_header
-                               (buf, sizeof(buf), hentry[H_BCC].body, NULL);
-                       compose->bcc = g_strdup(buf);
-               }
+               if (compose->mode == COMPOSE_REEDIT)
+                       compose->bcc =
+                               conv_unmime_header(hentry[H_BCC].body, NULL);
                g_free(hentry[H_BCC].body);
                hentry[H_BCC].body = NULL;
        }
@@ -1656,9 +2674,11 @@ static gint compose_parse_header(Compose *compose, MsgInfo *msginfo)
                hentry[H_NEWSGROUPS].body = NULL;
        }
        if (hentry[H_FOLLOWUP_TO].body != NULL) {
-               conv_unmime_header
-                       (buf, sizeof(buf), hentry[H_FOLLOWUP_TO].body, NULL);
-               compose->followup_to = g_strdup(buf);
+               if (hentry[H_FOLLOWUP_TO].body[0] != '\0') {
+                       compose->followup_to =
+                               conv_unmime_header(hentry[H_FOLLOWUP_TO].body,
+                                                  NULL);
+               }
                g_free(hentry[H_FOLLOWUP_TO].body);
                hentry[H_FOLLOWUP_TO].body = NULL;
        }
@@ -1668,7 +2688,7 @@ static gint compose_parse_header(Compose *compose, MsgInfo *msginfo)
                extract_address(hentry[H_LIST_POST].body);
                if (hentry[H_LIST_POST].body[0] != '\0') {
                        scan_mailto_url(hentry[H_LIST_POST].body,
-                                       &to, NULL, NULL, NULL, NULL);
+                                       NULL, &to, NULL, NULL, NULL, NULL, NULL);
                        if (to) {
                                g_free(compose->ml_post);
                                compose->ml_post = to;
@@ -1763,7 +2783,7 @@ static gchar *compose_parse_references(const gchar *ref, const gchar *msgid)
        for (cur = ref_id_list; cur != NULL; cur = cur->next) {
                if (new_ref->len > 0)
                        g_string_append(new_ref, "\n\t");
-               g_string_sprintfa(new_ref, "<%s>", (gchar *)cur->data);
+               g_string_append_printf(new_ref, "<%s>", (gchar *)cur->data);
        }
 
        slist_free_strings(ref_id_list);
@@ -1777,21 +2797,36 @@ static gchar *compose_parse_references(const gchar *ref, const gchar *msgid)
 
 static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
                                const gchar *fmt, const gchar *qmark,
-                               const gchar *body)
+                               const gchar *body, gboolean rewrap,
+                               gboolean need_unescape,
+                               const gchar *err_msg)
 {
-       GtkSText *text = GTK_STEXT(compose->text);
-       static MsgInfo dummyinfo;
+       MsgInfo* dummyinfo = NULL;
        gchar *quote_str = NULL;
        gchar *buf;
-       gchar *p, *lastp;
-       gint len;
+       gboolean prev_autowrap;
        const gchar *trimmed_body = body;
+       gint cursor_pos = -1;
+       GtkTextView *text = GTK_TEXT_VIEW(compose->text);
+       GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
+       GtkTextIter iter;
+       GtkTextMark *mark;
        
-       if (!msginfo)
-               msginfo = &dummyinfo;
 
-       if (qmark != NULL) {
-               quote_fmt_init(msginfo, NULL, NULL);
+       SIGNAL_BLOCK(buffer);
+
+       if (!msginfo) {
+               dummyinfo = compose_msginfo_new_from_compose(compose);
+               msginfo = dummyinfo;
+       }
+
+       if (qmark != NULL) {
+#ifdef USE_ENCHANT
+               quote_fmt_init(msginfo, NULL, NULL, FALSE, compose->account, FALSE,
+                               compose->gtkaspell);
+#else
+               quote_fmt_init(msginfo, NULL, NULL, FALSE, compose->account, FALSE);
+#endif
                quote_fmt_scan_string(qmark);
                quote_fmt_parse();
 
@@ -1799,43 +2834,143 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
                if (buf == NULL)
                        alertpanel_error(_("Quote mark format error."));
                else
-                       Xstrdup_a(quote_str, buf, return NULL)
+                       Xstrdup_a(quote_str, buf, goto error)
        }
 
        if (fmt && *fmt != '\0') {
-               while (trimmed_body && strlen(trimmed_body) > 1
-                       && trimmed_body[0]=='\n')
-                       *trimmed_body++;
 
-               quote_fmt_init(msginfo, quote_str, trimmed_body);
-               quote_fmt_scan_string(fmt);
-               quote_fmt_parse();
+               if (trimmed_body)
+                       while (*trimmed_body == '\n')
+                               trimmed_body++;
+
+#ifdef USE_ENCHANT
+               quote_fmt_init(msginfo, quote_str, trimmed_body, FALSE, compose->account, FALSE,
+                               compose->gtkaspell);
+#else
+               quote_fmt_init(msginfo, quote_str, trimmed_body, FALSE, compose->account, FALSE);
+#endif
+               if (need_unescape) {
+                       gchar *tmp = NULL;
+
+                       /* decode \-escape sequences in the internal representation of the quote format */
+                       tmp = malloc(strlen(fmt)+1);
+                       pref_get_unescaped_pref(tmp, fmt);
+                       quote_fmt_scan_string(tmp);
+                       quote_fmt_parse();
+                       g_free(tmp);
+               } else {
+                       quote_fmt_scan_string(fmt);
+                       quote_fmt_parse();
+               }
 
                buf = quote_fmt_get_buffer();
                if (buf == NULL) {
-                       alertpanel_error(_("Message reply/forward format error."));
-                       return NULL;
+                       gint line = quote_fmt_get_line();
+                       alertpanel_error(err_msg, line);
+                       goto error;
                }
        } else
                buf = "";
 
-       gtk_stext_freeze(text);
+       prev_autowrap = compose->autowrap;
+       compose->autowrap = FALSE;
 
-       for (p = buf; *p != '\0'; ) {
-               lastp = strchr(p, '\n');
-               len = lastp ? lastp - p + 1 : -1;
-               gtk_stext_insert(text, NULL, NULL, NULL, p, len);
-               if (lastp)
-                       p = lastp + 1;
-               else
-                       break;
+       mark = gtk_text_buffer_get_insert(buffer);
+       gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
+       if (g_utf8_validate(buf, -1, NULL)) { 
+               gtk_text_buffer_insert(buffer, &iter, buf, -1);
+       } else {
+               gchar *tmpout = NULL;
+               tmpout = conv_codeset_strdup
+                       (buf, conv_get_locale_charset_str_no_utf8(),
+                        CS_INTERNAL);
+               if (!tmpout || !g_utf8_validate(tmpout, -1, NULL)) {
+                       g_free(tmpout);
+                       tmpout = g_malloc(strlen(buf)*2+1);
+                       conv_localetodisp(tmpout, strlen(buf)*2+1, buf);
+               }
+               gtk_text_buffer_insert(buffer, &iter, tmpout, -1);
+               g_free(tmpout);
        }
 
-       gtk_stext_thaw(text);
+       cursor_pos = quote_fmt_get_cursor_pos();
+       if (cursor_pos == -1)
+               cursor_pos = gtk_text_iter_get_offset(&iter);
+       compose->set_cursor_pos = cursor_pos;
+
+       gtk_text_buffer_get_start_iter(buffer, &iter);
+       gtk_text_buffer_get_iter_at_offset(buffer, &iter, cursor_pos);
+       gtk_text_buffer_place_cursor(buffer, &iter);
+
+       compose->autowrap = prev_autowrap;
+       if (compose->autowrap && rewrap)
+               compose_wrap_all(compose);
+
+       goto ok;
+
+error:
+       buf = NULL;
+ok:
+       SIGNAL_UNBLOCK(buffer);
+
+       procmsg_msginfo_free( dummyinfo );
 
        return buf;
 }
 
+/* if ml_post is of type addr@host and from is of type
+ * addr-anything@host, return TRUE
+ */
+static gboolean is_subscription(const gchar *ml_post, const gchar *from)
+{
+       gchar *left_ml = NULL;
+       gchar *right_ml = NULL;
+       gchar *left_from = NULL;
+       gchar *right_from = NULL;
+       gboolean result = FALSE;
+       
+       if (!ml_post || !from)
+               return FALSE;
+       
+       left_ml = g_strdup(ml_post);
+       if (strstr(left_ml, "@")) {
+               right_ml = strstr(left_ml, "@")+1;
+               *(strstr(left_ml, "@")) = '\0';
+       }
+       
+       left_from = g_strdup(from);
+       if (strstr(left_from, "@")) {
+               right_from = strstr(left_from, "@")+1;
+               *(strstr(left_from, "@")) = '\0';
+       }
+       
+       if (left_ml && left_from && right_ml && right_from
+       &&  !strncmp(left_from, left_ml, strlen(left_ml))
+       &&  !strcmp(right_from, right_ml)) {
+               result = TRUE;
+       }
+       g_free(left_ml);
+       g_free(left_from);
+       
+       return result;
+}
+
+static gboolean same_address(const gchar *addr1, const gchar *addr2)
+{
+       gchar *my_addr1, *my_addr2;
+       
+       if (!addr1 || !addr2)
+               return FALSE;
+
+       Xstrdup_a(my_addr1, addr1, return FALSE);
+       Xstrdup_a(my_addr2, addr2, return FALSE);
+       
+       extract_address(my_addr1);
+       extract_address(my_addr2);
+       
+       return !strcasecmp(my_addr1, my_addr2);
+}
+
 static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
                                    gboolean to_all, gboolean to_ml,
                                    gboolean to_sender,
@@ -1847,27 +2982,87 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
        gchar *replyto = NULL;
        GHashTable *to_table;
 
-       g_return_if_fail(compose->account != NULL);
-       g_return_if_fail(msginfo != NULL);
+       gboolean reply_to_ml = FALSE;
+       gboolean default_reply_to = FALSE;
+
+       cm_return_if_fail(compose->account != NULL);
+       cm_return_if_fail(msginfo != NULL);
+
+       reply_to_ml = to_ml && compose->ml_post;
+
+       default_reply_to = msginfo->folder && 
+               msginfo->folder->prefs->enable_default_reply_to;
 
        if (compose->account->protocol != A_NNTP) {
-               if (!compose->replyto && to_ml && compose->ml_post
-                   && !(msginfo->folder && msginfo->folder->prefs->enable_default_reply_to))
-                       compose_entry_append(compose,
+               if (reply_to_ml && !default_reply_to) {
+                       
+                       gboolean is_subscr = is_subscription(compose->ml_post,
+                                                            msginfo->from);
+                       if (!is_subscr) {
+                               /* normal answer to ml post with a reply-to */
+                               compose_entry_append(compose,
                                           compose->ml_post,
                                           COMPOSE_TO);
-               else if (!(to_all || to_sender)
-                        && msginfo->folder
-                        && msginfo->folder->prefs->enable_default_reply_to) {
+                               if (compose->replyto
+                               &&  !same_address(compose->ml_post, compose->replyto))
+                                       compose_entry_append(compose,
+                                               compose->replyto,
+                                               COMPOSE_CC);
+                       } else {
+                               /* answer to subscription confirmation */
+                               if (compose->replyto)
+                                       compose_entry_append(compose,
+                                               compose->replyto,
+                                               COMPOSE_TO);
+                               else if (msginfo->from)
+                                       compose_entry_append(compose,
+                                               msginfo->from,
+                                               COMPOSE_TO);
+                       }
+               }
+               else if (!(to_all || to_sender) && default_reply_to) {
                        compose_entry_append(compose,
                            msginfo->folder->prefs->default_reply_to,
                            COMPOSE_TO);
-               } else
-                       compose_entry_append(compose,
+                       compose_entry_mark_default_to(compose,
+                               msginfo->folder->prefs->default_reply_to);
+               } else {
+                       gchar *tmp1 = NULL;
+                       if (!msginfo->from)
+                               return;
+                       Xstrdup_a(tmp1, msginfo->from, return);
+                       extract_address(tmp1);
+                       if (to_all || to_sender ||
+                           !account_find_from_address(tmp1, FALSE))
+                               compose_entry_append(compose,
                                 (compose->replyto && !to_sender)
-                                 ? compose->replyto :
-                                 msginfo->from ? msginfo->from : "",
-                                 COMPOSE_TO);
+                                         ? compose->replyto :
+                                         msginfo->from ? msginfo->from : "",
+                                         COMPOSE_TO);
+                       else if (!to_all && !to_sender) {
+                               if (!folder_has_parent_of_type(msginfo->folder, F_QUEUE) &&
+                                   !folder_has_parent_of_type(msginfo->folder, F_OUTBOX) &&
+                                   !folder_has_parent_of_type(msginfo->folder, F_DRAFT)) {
+                                       if (compose->replyto) {
+                                               compose_entry_append(compose,
+                                                       compose->replyto,
+                                                       COMPOSE_TO);
+                                       } else {
+                                               compose_entry_append(compose,
+                                                         msginfo->from ? msginfo->from : "",
+                                                         COMPOSE_TO);
+                                       }
+                               } else {
+                                       /* replying to own mail, use original recp */
+                                       compose_entry_append(compose,
+                                                 msginfo->to ? msginfo->to : "",
+                                                 COMPOSE_TO);
+                                       compose_entry_append(compose,
+                                                 msginfo->cc ? msginfo->cc : "",
+                                                 COMPOSE_CC);
+                               }
+                       }
+               }
        } else {
                if (to_sender || (compose->followup_to && 
                        !strncmp(compose->followup_to, "poster", 6)))
@@ -1900,7 +3095,7 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
 
        if (msginfo->subject && *msginfo->subject) {
                gchar *buf, *buf2;
-               guchar *p;
+               gchar *p;
 
                buf = p = g_strdup(msginfo->subject);
                p += subject_get_prefix_length(p);
@@ -1937,17 +3132,17 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
 
        to_table = g_hash_table_new(g_str_hash, g_str_equal);
        if (replyto)
-               g_hash_table_insert(to_table, g_strdup(replyto), GINT_TO_POINTER(1));
-       if (compose->account)
-               g_hash_table_insert(to_table, g_strdup(compose->account->address),
+               g_hash_table_insert(to_table, g_utf8_strdown(replyto, -1), GINT_TO_POINTER(1));
+       if (compose->account) {
+               g_hash_table_insert(to_table, g_utf8_strdown(compose->account->address, -1),
                                    GINT_TO_POINTER(1));
-
+       }
        /* remove address on To: and that of current account */
        for (cur = cc_list; cur != NULL; ) {
                GSList *next = cur->next;
                gchar *addr;
 
-               addr = g_strdup(cur->data);
+               addr = g_utf8_strdown(cur->data, -1);
                extract_address(addr);
 
                if (GPOINTER_TO_INT(g_hash_table_lookup(to_table, addr)) == 1)
@@ -1984,9 +3179,10 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
 
 static void compose_reedit_set_entry(Compose *compose, MsgInfo *msginfo)
 {
-       g_return_if_fail(msginfo != NULL);
+       cm_return_if_fail(msginfo != NULL);
 
        SET_ENTRY(subject_entry, msginfo->subject);
+       SET_ENTRY(from_name, msginfo->from);
        SET_ADDRESS(COMPOSE_TO, msginfo->to);
        SET_ADDRESS(COMPOSE_CC, compose->cc);
        SET_ADDRESS(COMPOSE_BCC, compose->bcc);
@@ -1995,7 +3191,7 @@ static void compose_reedit_set_entry(Compose *compose, MsgInfo *msginfo)
        SET_ADDRESS(COMPOSE_FOLLOWUPTO, compose->followup_to);
 
        compose_update_priority_menu_item(compose);
-       compose_update_privacy_system_menu_item(compose);
+       compose_update_privacy_system_menu_item(compose, FALSE);
        compose_show_first_last_header(compose, TRUE);
 }
 
@@ -2004,127 +3200,165 @@ static void compose_reedit_set_entry(Compose *compose, MsgInfo *msginfo)
 
 static void compose_insert_sig(Compose *compose, gboolean replace)
 {
-       GtkSText *text = GTK_STEXT(compose->text);
-       gint cur_pos;
-       gint len;
+       GtkTextView *text = GTK_TEXT_VIEW(compose->text);
+       GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
+       GtkTextMark *mark;
+       GtkTextIter iter, iter_end;
+       gint cur_pos, ins_pos;
+       gboolean prev_autowrap;
+       gboolean found = FALSE;
+       gboolean exists = FALSE;
+       
+       cm_return_if_fail(compose->account != NULL);
+
+       BLOCK_WRAP();
 
-       g_return_if_fail(compose->account != NULL);
+       g_signal_handlers_block_by_func(G_OBJECT(buffer),
+                                       G_CALLBACK(compose_changed_cb),
+                                       compose);
+       
+       mark = gtk_text_buffer_get_insert(buffer);
+       gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
+       cur_pos = gtk_text_iter_get_offset (&iter);
+       ins_pos = cur_pos;
 
-       cur_pos = gtk_editable_get_position(GTK_EDITABLE(text));
+       gtk_text_buffer_get_end_iter(buffer, &iter);
 
-       gtk_stext_freeze(text);
+       exists = (compose->sig_str != NULL);
 
        if (replace) {
-               len = gtk_stext_get_length(text);
-               gtk_stext_set_point(text, len);
-       }
+               GtkTextIter first_iter, start_iter, end_iter;
 
-       if (replace && compose->sig_str) {
-               gint pos;
+               gtk_text_buffer_get_start_iter(buffer, &first_iter);
 
-               if (compose->sig_str[0] == '\0')
-                       pos = -1;
+               if (!exists || compose->sig_str[0] == '\0')
+                       found = FALSE;
                else
-                       pos = gtkut_stext_find(text, 0, compose->sig_str, TRUE);
-
-               if (pos != -1) {
-                       len = get_mbs_len(compose->sig_str);
-                       if (len >= 0) {
-                               gtk_stext_set_point(text, pos);
-                               gtk_stext_forward_delete(text, len);
+                       found = gtk_text_iter_forward_to_tag_toggle(&first_iter,
+                                       compose->signature_tag);
+
+               if (found) {
+                       /* include previous \n\n */
+                       gtk_text_iter_backward_chars(&first_iter, 1);
+                       start_iter = first_iter;
+                       end_iter = first_iter;
+                       /* skip re-start */
+                       found = gtk_text_iter_forward_to_tag_toggle(&end_iter,
+                                       compose->signature_tag);
+                       found &= gtk_text_iter_forward_to_tag_toggle(&end_iter,
+                                       compose->signature_tag);
+                       if (found) {
+                               gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
+                               iter = start_iter;
                        }
-               }
-       }
+               } 
+       } 
 
        g_free(compose->sig_str);
-       compose->sig_str = compose_get_signature_str(compose);
-       if (!compose->sig_str || (replace && !compose->account->auto_sig))
-               compose->sig_str = g_strdup("");
-
-       gtk_stext_insert(text, NULL, NULL, NULL, compose->sig_str, -1);
-
-       gtk_stext_thaw(text);
-
-       if (cur_pos > gtk_stext_get_length(text))
-               cur_pos = gtk_stext_get_length(text);
-
-       gtk_editable_set_position(GTK_EDITABLE(text), cur_pos);
-       gtk_stext_set_point(text, cur_pos);
-}
-
-static gchar *compose_get_signature_str(Compose *compose)
-{
-       gchar *sig_body = NULL;
-       gchar *sig_str = NULL;
-
-       g_return_val_if_fail(compose->account != NULL, NULL);
+       compose->sig_str = account_get_signature_str(compose->account);
 
-       if (!compose->account->sig_path)
-               return NULL;
-
-       if (compose->account->sig_type == SIG_FILE) {
-               if (!is_file_or_fifo_exist(compose->account->sig_path)) {
-                       g_warning("can't open signature file: %s\n",
-                                 compose->account->sig_path);
-                       return NULL;
-               }
-       }
-
-       if (compose->account->sig_type == SIG_COMMAND)
-               sig_body = get_command_output(compose->account->sig_path);
-       else {
-               gchar *tmp;
+       cur_pos = gtk_text_iter_get_offset(&iter);
 
-               tmp = file_read_to_str(compose->account->sig_path);
-               if (!tmp)
-                       return NULL;
-               sig_body = normalize_newlines(tmp);
-               g_free(tmp);
-       }
-
-       if (compose->account->sig_sep)
-               sig_str = g_strconcat("\n\n", compose->account->sig_sep, "\n", sig_body,
-                                     NULL);
+       if (!compose->sig_str || (replace && !compose->account->auto_sig)) {
+               g_free(compose->sig_str);
+               compose->sig_str = NULL;
+       } else {
+               if (compose->sig_inserted == FALSE)
+                       gtk_text_buffer_insert(buffer, &iter, "\n", -1);
+               compose->sig_inserted = TRUE;
+
+               cur_pos = gtk_text_iter_get_offset(&iter);
+               gtk_text_buffer_insert(buffer, &iter, compose->sig_str, -1);
+               /* remove \n\n */
+               gtk_text_buffer_get_iter_at_offset(buffer, &iter, cur_pos);
+               gtk_text_iter_forward_chars(&iter, 1);
+               gtk_text_buffer_get_end_iter(buffer, &iter_end);
+               gtk_text_buffer_apply_tag_by_name(buffer,"signature",&iter, &iter_end);
+
+               if (cur_pos > gtk_text_buffer_get_char_count (buffer))
+                       cur_pos = gtk_text_buffer_get_char_count (buffer);
+       }
+
+       /* put the cursor where it should be 
+        * either where the quote_fmt says, either where it was */
+       if (compose->set_cursor_pos < 0)
+               gtk_text_buffer_get_iter_at_offset(buffer, &iter, ins_pos);
        else
-               sig_str = g_strconcat("\n\n", sig_body, NULL);
-
-       g_free(sig_body);
+               gtk_text_buffer_get_iter_at_offset(buffer, &iter, 
+                       compose->set_cursor_pos);
        
-       return sig_str;
+       compose->set_cursor_pos = -1;
+       gtk_text_buffer_place_cursor(buffer, &iter);
+       g_signal_handlers_unblock_by_func(G_OBJECT(buffer),
+                                       G_CALLBACK(compose_changed_cb),
+                                       compose);
+               
+       UNBLOCK_WRAP();
 }
 
 static ComposeInsertResult compose_insert_file(Compose *compose, const gchar *file)
 {
-       GtkSText *text = GTK_STEXT(compose->text);
+       GtkTextView *text;
+       GtkTextBuffer *buffer;
+       GtkTextMark *mark;
+       GtkTextIter iter;
+       const gchar *cur_encoding;
        gchar buf[BUFFSIZE];
        gint len;
        FILE *fp;
+       gboolean prev_autowrap;
        gboolean badtxt = FALSE;
 
-       g_return_val_if_fail(file != NULL, COMPOSE_INSERT_NO_FILE);
+       cm_return_val_if_fail(file != NULL, COMPOSE_INSERT_NO_FILE);
 
-       if ((fp = fopen(file, "rb")) == NULL) {
+       if ((fp = g_fopen(file, "rb")) == NULL) {
                FILE_OP_ERROR(file, "fopen");
                return COMPOSE_INSERT_READ_ERROR;
        }
 
-       gtk_stext_freeze(text);
+       prev_autowrap = compose->autowrap;
+       compose->autowrap = FALSE;
+
+       text = GTK_TEXT_VIEW(compose->text);
+       buffer = gtk_text_view_get_buffer(text);
+       mark = gtk_text_buffer_get_insert(buffer);
+       gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
+
+       g_signal_handlers_block_by_func(G_OBJECT(buffer),
+                                       G_CALLBACK(text_inserted),
+                                       compose);
+
+       cur_encoding = conv_get_locale_charset_str_no_utf8();
 
        while (fgets(buf, sizeof(buf), fp) != NULL) {
+               gchar *str;
+
+               if (g_utf8_validate(buf, -1, NULL) == TRUE)
+                       str = g_strdup(buf);
+               else
+                       str = conv_codeset_strdup
+                               (buf, cur_encoding, CS_INTERNAL);
+               if (!str) continue;
+
                /* strip <CR> if DOS/Windows file,
                   replace <CR> with <LF> if Macintosh file. */
-               strcrchomp(buf);
-               len = strlen(buf);
-               if (len > 0 && buf[len - 1] != '\n') {
+               strcrchomp(str);
+               len = strlen(str);
+               if (len > 0 && str[len - 1] != '\n') {
                        while (--len >= 0)
-                               if (buf[len] == '\r') buf[len] = '\n';
+                               if (str[len] == '\r') str[len] = '\n';
                }
-               if (mbstowcs(NULL, buf, 0) == -1)
-                       badtxt = TRUE;
-               gtk_stext_insert(text, NULL, NULL, NULL, buf, -1);
+
+               gtk_text_buffer_insert(buffer, &iter, str, -1);
+               g_free(str);
        }
 
-       gtk_stext_thaw(text);
+       g_signal_handlers_unblock_by_func(G_OBJECT(buffer),
+                                         G_CALLBACK(text_inserted),
+                                         compose);
+       compose->autowrap = prev_autowrap;
+       if (compose->autowrap)
+               compose_wrap_all(compose);
 
        fclose(fp);
 
@@ -2134,128 +3368,140 @@ static ComposeInsertResult compose_insert_file(Compose *compose, const gchar *fi
                return COMPOSE_INSERT_SUCCESS;
 }
 
-static void compose_attach_append(Compose *compose, const gchar *file,
+static gboolean compose_attach_append(Compose *compose, const gchar *file,
                                  const gchar *filename,
                                  const gchar *content_type)
 {
        AttachInfo *ainfo;
-       gchar *text[N_ATTACH_COLS];
+       GtkTreeIter iter;
        FILE *fp;
        off_t size;
-       gint row;
+       GAuto *auto_ainfo;
+       gchar *size_text;
+       GtkListStore *store;
+       gchar *name;
+       gboolean has_binary = FALSE;
 
        if (!is_file_exist(file)) {
-               g_warning("File %s doesn't exist\n", file);
-               return;
+               gchar *file_from_uri = g_filename_from_uri(file, NULL, NULL);
+               gboolean result = FALSE;
+               if (file_from_uri && is_file_exist(file_from_uri)) {
+                       result = compose_attach_append(
+                                               compose, file_from_uri,
+                                               filename,
+                                               content_type);
+               }
+               g_free(file_from_uri);
+               if (result)
+                       return TRUE;
+               alertpanel_error("File %s doesn't exist\n", filename);
+               return FALSE;
        }
        if ((size = get_file_size(file)) < 0) {
-               g_warning("Can't get file size of %s\n", file);
-               return;
+               alertpanel_error("Can't get file size of %s\n", filename);
+               return FALSE;
        }
        if (size == 0) {
-               alertpanel_notice(_("File %s is empty."), file);
-               return;
+               alertpanel_error(_("File %s is empty."), filename);
+               return FALSE;
        }
-       if ((fp = fopen(file, "rb")) == NULL) {
-               alertpanel_error(_("Can't read %s."), file);
-               return;
+       if ((fp = g_fopen(file, "rb")) == NULL) {
+               alertpanel_error(_("Can't read %s."), filename);
+               return FALSE;
        }
        fclose(fp);
 
-#if 0 /* NEW COMPOSE GUI */
-       if (!compose->use_attach) {
-               GtkItemFactory *ifactory;
-
-               ifactory = gtk_item_factory_from_widget(compose->menubar);
-               menu_set_active(ifactory, "/View/Attachment", TRUE);
-       }
-#endif
        ainfo = g_new0(AttachInfo, 1);
+       auto_ainfo = g_auto_pointer_new_with_free
+                       (ainfo, (GFreeFunc) compose_attach_info_free); 
        ainfo->file = g_strdup(file);
 
        if (content_type) {
                ainfo->content_type = g_strdup(content_type);
-               if (!g_strcasecmp(content_type, "message/rfc822")) {
+               if (!g_ascii_strcasecmp(content_type, "message/rfc822")) {
                        MsgInfo *msginfo;
                        MsgFlags flags = {0, 0};
-                       gchar *name;
 
-                       if (procmime_get_encoding_for_text_file(file) == ENC_7BIT)
+                       if (procmime_get_encoding_for_text_file(file, &has_binary) == ENC_7BIT)
                                ainfo->encoding = ENC_7BIT;
                        else
                                ainfo->encoding = ENC_8BIT;
 
                        msginfo = procheader_parse_file(file, flags, FALSE, FALSE);
                        if (msginfo && msginfo->subject)
-                               name = msginfo->subject;
+                               name = g_strdup(msginfo->subject);
                        else
-                               name = g_basename(filename ? filename : file);
+                               name = g_path_get_basename(filename ? filename : file);
 
                        ainfo->name = g_strdup_printf(_("Message: %s"), name);
 
                        procmsg_msginfo_free(msginfo);
                } else {
-                       if (!g_strncasecmp(content_type, "text", 4))
-                               ainfo->encoding = procmime_get_encoding_for_text_file(file);
+                       if (!g_ascii_strncasecmp(content_type, "text", 4))
+                               ainfo->encoding = procmime_get_encoding_for_text_file(file, &has_binary);
                        else
                                ainfo->encoding = ENC_BASE64;
-                       ainfo->name = g_strdup
-                               (g_basename(filename ? filename : file));
+                       name = g_path_get_basename(filename ? filename : file);
+                       ainfo->name = g_strdup(name);
                }
+               g_free(name);
        } 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;
-               } else if (!g_strncasecmp(ainfo->content_type, "text", 4))
+               } else if (!g_ascii_strncasecmp(ainfo->content_type, "text", 4))
                        ainfo->encoding =
-                               procmime_get_encoding_for_text_file(file);
+                               procmime_get_encoding_for_text_file(file, &has_binary);
                else
                        ainfo->encoding = ENC_BASE64;
-               ainfo->name = g_strdup(g_basename(filename ? filename : file)); 
+               name = g_path_get_basename(filename ? filename : file);
+               ainfo->name = g_strdup(name);   
+               g_free(name);
+       }
+
+       if (ainfo->name != NULL
+       &&  !strcmp(ainfo->name, ".")) {
+               g_free(ainfo->name);
+               ainfo->name = NULL;
        }
 
-       if (!strcmp(ainfo->content_type, "unknown")) {
+       if (!strcmp(ainfo->content_type, "unknown") || has_binary) {
                g_free(ainfo->content_type);
                ainfo->content_type = g_strdup("application/octet-stream");
        }
 
-       ainfo->size = size;
+       ainfo->size = (goffset)size;
+       size_text = to_human_readable((goffset)size);
 
-       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);
+       store = GTK_LIST_STORE(gtk_tree_view_get_model
+                       (GTK_TREE_VIEW(compose->attach_clist)));
+               
+       gtk_list_store_append(store, &iter);
+       gtk_list_store_set(store, &iter, 
+                          COL_MIMETYPE, ainfo->content_type,
+                          COL_SIZE, size_text,
+                          COL_NAME, ainfo->name,
+                          COL_DATA, ainfo,
+                          COL_AUTODATA, auto_ainfo,
+                          -1);
+       
+       g_auto_pointer_free(auto_ainfo);
+       compose_attach_update_label(compose);
+       return TRUE;
 }
 
 static void compose_use_signing(Compose *compose, gboolean use_signing)
 {
-       GtkItemFactory *ifactory;
-       GtkWidget *menuitem = NULL;
-
        compose->use_signing = use_signing;
-       ifactory = gtk_item_factory_from_widget(compose->menubar);
-       menuitem = gtk_item_factory_get_item
-               (ifactory, "/Options/Sign");
-       gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), 
-                                      use_signing);
+       cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/Sign", use_signing);
 }
 
 static void compose_use_encryption(Compose *compose, gboolean use_encryption)
 {
-       GtkItemFactory *ifactory;
-       GtkWidget *menuitem = NULL;
-
        compose->use_encryption = use_encryption;
-       ifactory = gtk_item_factory_from_widget(compose->menubar);
-       menuitem = gtk_item_factory_get_item
-               (ifactory, "/Options/Encrypt");
-
-       gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), 
-                                      use_encryption);
+       cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/Encrypt", use_encryption);
 }
 
 #define NEXT_PART_NOT_CHILD(info)  \
@@ -2289,23 +3535,20 @@ static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
        while (child && child->node->children && (child->type == MIMETYPE_MULTIPART))
                child = (MimeInfo *)child->node->children->data;
 
-       if (child->type == MIMETYPE_TEXT) {
-               firsttext = child;
-               debug_print("First text part found\n");
-       } else if (compose->mode == COMPOSE_REEDIT &&
-                child->type == MIMETYPE_APPLICATION &&
-                !g_strcasecmp(child->subtype, "pgp-encrypted")) {
-               AlertValue val;
-               val = alertpanel(_("Encrypted message"),
-                                _("Cannot re-edit an encrypted message. \n"
-                                  "Discard encrypted part?"),
-                                _("Yes"), _("No"), NULL);
-               if (val == G_ALERTDEFAULT) 
+       if (child) {
+               if (child->type == MIMETYPE_TEXT) {
+                       firsttext = child;
+                       debug_print("First text part found\n");
+               } else if (compose->mode == COMPOSE_REEDIT &&
+                        child->type == MIMETYPE_APPLICATION &&
+                        !g_ascii_strcasecmp(child->subtype, "pgp-encrypted")) {
                        encrypted = (MimeInfo *)child->node->parent->data;
+               }
        }
-     
        child = (MimeInfo *) mimeinfo->node->children->data;
        while (child != NULL) {
+               gint err;
+
                if (child == encrypted) {
                        /* skip this part of tree */
                        NEXT_PART_NOT_CHILD(child);
@@ -2324,17 +3567,29 @@ static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
                }
 
                outfile = procmime_get_tmp_file_name(child);
-               if (procmime_get_part(outfile, child) < 0)
-                       g_warning("Can't get the part of multipart message.");
+               if ((err = procmime_get_part(outfile, child)) < 0)
+                       g_warning("Can't get the part of multipart message. (%s)", strerror(-err));
                else {
                        gchar *content_type;
 
                        content_type = procmime_get_content_type_str(child->type, child->subtype);
-                       partname = procmime_mimeinfo_get_parameter(child, "name");
-                       if (partname == NULL)
-                               partname = "";
-                       compose_attach_append(compose, outfile, 
-                                             partname, content_type);
+
+                       /* if we meet a pgp signature, we don't attach it, but
+                        * we force signing. */
+                       if ((strcmp(content_type, "application/pgp-signature") &&
+                           strcmp(content_type, "application/pkcs7-signature") &&
+                           strcmp(content_type, "application/x-pkcs7-signature"))
+                           || compose->mode == COMPOSE_REDIRECT) {
+                               partname = procmime_mimeinfo_get_parameter(child, "filename");
+                               if (partname == NULL)
+                                       partname = procmime_mimeinfo_get_parameter(child, "name");
+                               if (partname == NULL)
+                                       partname = "";
+                               compose_attach_append(compose, outfile, 
+                                                     partname, content_type);
+                       } else {
+                               compose_force_signing(compose, compose->account, NULL);
+                       }
                        g_free(content_type);
                }
                g_free(outfile);
@@ -2345,620 +3600,838 @@ static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
 
 #undef NEXT_PART_NOT_CHILD
 
-#define GET_CHAR(pos, buf, len)                                                     \
-{                                                                           \
-       if (text->use_wchar)                                                 \
-               len = wctomb(buf, (wchar_t)GTK_STEXT_INDEX(text, (pos)));    \
-       else {                                                               \
-               buf[0] = GTK_STEXT_INDEX(text, (pos));                       \
-               len = 1;                                                     \
-       }                                                                    \
-}
-
-#define DISP_WIDTH(len) \
-       ((len > 2 && conv_get_current_charset() == C_UTF_8) ? 2 : \
-        (len == 2 && conv_get_current_charset() == C_UTF_8) ? 1 : len)
-
-#define SPACE_CHARS    " \t"
-
-static void compose_wrap_line(Compose *compose)
-{
-       GtkSText *text = GTK_STEXT(compose->text);
-       gint ch_len, last_ch_len;
-       gchar cbuf[MB_LEN_MAX], last_ch;
-       guint text_len;
-       guint line_end;
-       guint quoted;
-       gint p_start, p_end;
-       gint line_pos, cur_pos;
-       gint line_len, cur_len;
-
-       gtk_stext_freeze(text);
-
-       text_len = gtk_stext_get_length(text);
-
-       /* check to see if the point is on the paragraph mark (empty line). */
-       cur_pos = gtk_stext_get_point(text);
-       GET_CHAR(cur_pos, cbuf, ch_len);
-       if ((ch_len == 1 && *cbuf == '\n') || cur_pos == text_len) {
-               if (cur_pos == 0)
-                       goto compose_end; /* on the paragraph mark */
-               GET_CHAR(cur_pos - 1, cbuf, ch_len);
-               if (ch_len == 1 && *cbuf == '\n')
-                       goto compose_end; /* on the paragraph mark */
-       }
-
-       /* find paragraph start. */
-       line_end = quoted = 0;
-       for (p_start = cur_pos; p_start >= 0; --p_start) {
-               GET_CHAR(p_start, cbuf, ch_len);
-               if (ch_len == 1 && *cbuf == '\n') {
-                       if (quoted)
-                               goto compose_end; /* quoted part */
-                       if (line_end) {
-                               p_start += 2;
-                               break;
-                       }
-                       line_end = 1;
-               } else {
-                       if (ch_len == 1 
-                           && strchr(prefs_common.quote_chars, *cbuf))
-                               quoted = 1;
-                       else if (ch_len != 1 || !isspace(*(guchar *)cbuf))
-                               quoted = 0;
-
-                       line_end = 0;
-               }
-       }
-       if (p_start < 0)
-               p_start = 0;
-
-       /* find paragraph end. */
-       line_end = 0;
-       for (p_end = cur_pos; p_end < text_len; p_end++) {
-               GET_CHAR(p_end, cbuf, ch_len);
-               if (ch_len == 1 && *cbuf == '\n') {
-                       if (line_end) {
-                               p_end -= 1;
-                               break;
-                       }
-                       line_end = 1;
-               } else {
-                       if (line_end && ch_len == 1 &&
-                           strchr(prefs_common.quote_chars, *cbuf))
-                               goto compose_end; /* quoted part */
-
-                       line_end = 0;
-               }
-       }
-       if (p_end >= text_len)
-               p_end = text_len;
-
-       if (p_start >= p_end)
-               goto compose_end;
-
-       line_len = cur_len = 0;
-       last_ch_len = 0;
-       last_ch = '\0';
-       line_pos = p_start;
-       for (cur_pos = p_start; cur_pos < p_end; cur_pos++) {
-               guint space = 0;
-
-               GET_CHAR(cur_pos, cbuf, ch_len);
-
-               if (ch_len < 0) {
-                       cbuf[0] = '\0';
-                       ch_len = 1;
-               }
-
-               if (ch_len == 1 && isspace(*(guchar *)cbuf))
-                       space = 1;
-
-               if (ch_len == 1 && *cbuf == '\n') {
-                       guint replace = 0;
-                       if (last_ch_len == 1 && !isspace((guchar)last_ch)) {
-                               if (cur_pos + 1 < p_end) {
-                                       GET_CHAR(cur_pos + 1, cbuf, ch_len);
-                                       if (ch_len == 1 &&
-                                           !isspace(*(guchar *)cbuf))
-                                               replace = 1;
-                               }
-                       }
-                       gtk_stext_set_point(text, cur_pos + 1);
-                       gtk_stext_backward_delete(text, 1);
-                       if (replace) {
-                               gtk_stext_set_point(text, cur_pos);
-                               gtk_stext_insert(text, NULL, NULL, NULL, " ", 1);
-                               space = 1;
-                       }
-                       else {
-                               p_end--;
-                               cur_pos--;
-                               continue;
-                       }
-               }
-
-               last_ch_len = ch_len;
-               last_ch = *cbuf;
-
-               if (space) {
-                       line_pos = cur_pos + 1;
-                       line_len = cur_len + ch_len;
-               }
-
-               if (cur_len + DISP_WIDTH(ch_len) > prefs_common.linewrap_len &&
-                   line_len > 0) {
-                       gint tlen = ch_len;
-
-                       GET_CHAR(line_pos - 1, cbuf, ch_len);
-                       if (ch_len == 1 && isspace(*(guchar *)cbuf)) {
-                               gtk_stext_set_point(text, line_pos);
-                               gtk_stext_backward_delete(text, 1);
-                               p_end--;
-                               cur_pos--;
-                               line_pos--;
-                               cur_len--;
-                               line_len--;
-                       }
-                       ch_len = tlen;
-
-                       gtk_stext_set_point(text, line_pos);
-                       gtk_stext_insert(text, NULL, NULL, NULL, "\n", 1);
-                       p_end++;
-                       cur_pos++;
-                       line_pos++;
-                       cur_len = cur_len - line_len + DISP_WIDTH(ch_len);
-                       line_len = 0;
-                       continue;
-               }
-
-               if (ch_len > 1) {
-                       line_pos = cur_pos + 1;
-                       line_len = cur_len + DISP_WIDTH(ch_len);
-               }
-               cur_len += DISP_WIDTH(ch_len);
-       }
-
-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, clen;
-       gchar cbuf[MB_LEN_MAX];
 
-       printf("%d [", pos);
-       for (i = pos; i < tlen; i++) {
-               GET_CHAR(i, cbuf, clen);
-               if (clen < 0) break;
-               if (breakoncr && clen == 1 && cbuf[0] == '\n')
-                       break;
-               fwrite(cbuf, clen, 1, stdout);
-       }
-       printf("]\n");
-}
-#endif
 
 typedef enum {
-       WAIT_FOR_SPACE,
        WAIT_FOR_INDENT_CHAR,
-       WAIT_FOR_INDENT_CHAR_OR_SPACE
+       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)
-{
-       guint i_len = 0;
-       guint i, ch_len, alnum_cnt = 0;
+   indent characters followed by indent characters or spaces/tabs,
+   alphabets and numbers immediately followed by indent characters,
+   and the repeating sequences of the above
+   If quote ends with multiple spaces, only the first one is included. */
+static gchar *compose_get_quote_str(GtkTextBuffer *buffer,
+                                   const GtkTextIter *start, gint *len)
+{
+       GtkTextIter iter = *start;
+       gunichar wc;
+       gchar ch[6];
+       gint clen;
        IndentState state = WAIT_FOR_INDENT_CHAR;
-       gchar cbuf[MB_LEN_MAX];
        gboolean is_space;
        gboolean is_indent;
+       gint alnum_count = 0;
+       gint space_count = 0;
+       gint quote_len = 0;
 
        if (prefs_common.quote_chars == NULL) {
                return 0 ;
        }
 
-       for (i = start_pos; i < text_len; i++) {
-               GET_CHAR(i, cbuf, ch_len);
-               if (ch_len > 1)
+       while (!gtk_text_iter_ends_line(&iter)) {
+               wc = gtk_text_iter_get_char(&iter);
+               if (g_unichar_iswide(wc))
                        break;
-
-               if (cbuf[0] == '\n')
+               clen = g_unichar_to_utf8(wc, ch);
+               if (clen != 1)
                        break;
 
-               is_indent = strchr(prefs_common.quote_chars, cbuf[0]) ? TRUE : FALSE;
-               is_space = strchr(SPACE_CHARS, cbuf[0]) ? TRUE : FALSE;
+               is_indent = strchr(prefs_common.quote_chars, ch[0]) ? TRUE : FALSE;
+               is_space = g_unichar_isspace(wc);
 
-               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((guchar)cbuf[0]))
-                               goto out;
-                       if (is_space == TRUE) {
-                               alnum_cnt = 0;
+               if (state == WAIT_FOR_INDENT_CHAR) {
+                       if (!is_indent && !g_unichar_isalnum(wc))
+                               break;
+                       if (is_indent) {
+                               quote_len += alnum_count + space_count + 1;
+                               alnum_count = space_count = 0;
                                state = WAIT_FOR_INDENT_CHAR_OR_SPACE;
-                       } else if (is_indent == TRUE) {
-                               alnum_cnt = 0;
-                               state = WAIT_FOR_SPACE;
+                       } else
+                               alnum_count++;
+               } else if (state == WAIT_FOR_INDENT_CHAR_OR_SPACE) {
+                       if (!is_indent && !is_space && !g_unichar_isalnum(wc))
+                               break;
+                       if (is_space)
+                               space_count++;
+                       else if (is_indent) {
+                               quote_len += alnum_count + space_count + 1;
+                               alnum_count = space_count = 0;
                        } else {
-                               alnum_cnt++;
+                               alnum_count++;
                                state = WAIT_FOR_INDENT_CHAR;
                        }
-                       break;
-               case WAIT_FOR_INDENT_CHAR:
-                       if (is_indent == FALSE && !isupper((guchar)cbuf[0]))
-                               goto out;
-                       if (is_indent == TRUE) {
-                               if (alnum_cnt > 0 
-                                   && !strchr(prefs_common.quote_chars, cbuf[0]))
-                                       goto out;
-                               alnum_cnt = 0;
-                               state = WAIT_FOR_SPACE;
-                       } else {
-                               alnum_cnt++;
-                       }
-                       break;
                }
 
-               i_len++;
+               gtk_text_iter_forward_char(&iter);
        }
 
-out:
-       if ((i_len > 0) && (state == WAIT_FOR_INDENT_CHAR))
-               i_len -= alnum_cnt;
-
-       return i_len;
-}
+       if (quote_len > 0 && space_count > 0)
+               quote_len++;
 
-/* insert quotation string when line was wrapped */
-static guint ins_quote(GtkSText *text, guint indent_len,
-                      guint prev_line_pos, guint text_len,
-                      gchar *quote_fmt)
-{
-       guint i, ins_len = 0;
-       gchar ch;
+       if (len)
+               *len = quote_len;
 
-       if (indent_len) {
-               for (i = 0; i < indent_len; i++) {
-                       ch = GTK_STEXT_INDEX(text, prev_line_pos + i);
-                       gtk_stext_insert(text, NULL, NULL, NULL, &ch, 1);
-               }
-               ins_len = indent_len;
+       if (quote_len > 0) {
+               iter = *start;
+               gtk_text_iter_forward_chars(&iter, quote_len);
+               return gtk_text_buffer_get_text(buffer, start, &iter, FALSE);
        }
 
-       return ins_len;
+       return NULL;
 }
 
-/* check if we should join the next line */
-static gboolean join_next_line(GtkSText *text, guint start_pos, guint tlen,
-                              guint prev_ilen, gboolean autowrap)
+/* return >0 if the line is itemized */
+static int compose_itemized_length(GtkTextBuffer *buffer,
+                                   const GtkTextIter *start)
 {
-       guint indent_len, ch_len;
-       gboolean do_join = FALSE;
-       gchar cbuf[MB_LEN_MAX];
-
-       indent_len = get_indent_length(text, start_pos, tlen);
+       GtkTextIter iter = *start;
+       gunichar wc;
+       gchar ch[6];
+       gint clen;
+       gint len = 0;
+       if (gtk_text_iter_ends_line(&iter))
+               return 0;
 
-       if ((autowrap || 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;
+       while (1) {
+               len++;
+               wc = gtk_text_iter_get_char(&iter);
+               if (!g_unichar_isspace(wc))
+                       break;
+               gtk_text_iter_forward_char(&iter);
+               if (gtk_text_iter_ends_line(&iter))
+                       return 0;
        }
 
-       return do_join;
+       clen = g_unichar_to_utf8(wc, ch);
+       if (clen != 1)
+               return 0;
+
+       if (!strchr("*-+", ch[0]))
+               return 0;
+
+       gtk_text_iter_forward_char(&iter);
+       if (gtk_text_iter_ends_line(&iter))
+               return 0;
+       wc = gtk_text_iter_get_char(&iter);
+       if (g_unichar_isspace(wc)) {
+               return len+1;
+       }
+       return 0;
 }
 
-static void compose_wrap_line_all(Compose *compose)
+/* return the string at the start of the itemization */
+static gchar * compose_get_itemized_chars(GtkTextBuffer *buffer,
+                                   const GtkTextIter *start)
 {
-       compose_wrap_line_all_full(compose, FALSE);
-}
+       GtkTextIter iter = *start;
+       gunichar wc;
+       gint len = 0;
+       GString *item_chars = g_string_new("");
+       gchar *str = NULL;
 
-#define STEXT_FREEZE() \
-       if (!frozen) { gtk_stext_freeze(text); frozen = TRUE; }
+       if (gtk_text_iter_ends_line(&iter))
+               return NULL;
 
-static void compose_wrap_line_all_full(Compose *compose, gboolean autowrap)
-{
-       GtkSText *text = GTK_STEXT(compose->text);
-       guint tlen;
-       guint line_pos = 0, cur_pos = 0, p_pos = 0;
-       gint line_len = 0, cur_len = 0;
-       gint ch_len;
-       gboolean is_new_line = TRUE, do_delete = FALSE;
-       guint i_len = 0;
-       gboolean linewrap_quote = prefs_common.linewrap_quote;
-       gboolean set_editable_pos = FALSE;
-       gint editable_pos = 0;
-       gboolean frozen = FALSE;
-       guint linewrap_len = prefs_common.linewrap_len;
-       gchar *qfmt = prefs_common.quotemark;
-       gchar cbuf[MB_LEN_MAX];
+       while (1) {
+               len++;
+               wc = gtk_text_iter_get_char(&iter);
+               if (!g_unichar_isspace(wc))
+                       break;
+               gtk_text_iter_forward_char(&iter);
+               if (gtk_text_iter_ends_line(&iter))
+                       break;
+               g_string_append_unichar(item_chars, wc);
+       }
 
-       tlen = gtk_stext_get_length(text);
+       str = item_chars->str;
+       g_string_free(item_chars, FALSE);
+       return str;
+}
 
-       for (; cur_pos < tlen; cur_pos++) {
-               /* mark position of new line - needed for quotation wrap */
-               if (is_new_line) {
-                       if (linewrap_quote)
-                               i_len = get_indent_length(text, cur_pos, tlen);
+/* return the number of spaces at a line's start */
+static int compose_left_offset_length(GtkTextBuffer *buffer,
+                                   const GtkTextIter *start)
+{
+       GtkTextIter iter = *start;
+       gunichar wc;
+       gint len = 0;
+       if (gtk_text_iter_ends_line(&iter))
+               return 0;
 
-                       is_new_line = FALSE;
-                       p_pos = cur_pos;
-#ifdef WRAP_DEBUG
-                       g_print("new line i_len=%d p_pos=", i_len);
-                       dump_text(text, p_pos, tlen, 1);
-#endif
-               }
+       while (1) {
+               wc = gtk_text_iter_get_char(&iter);
+               if (!g_unichar_isspace(wc))
+                       break;
+               len++;
+               gtk_text_iter_forward_char(&iter);
+               if (gtk_text_iter_ends_line(&iter))
+                       return 0;
+       }
 
-               GET_CHAR(cur_pos, cbuf, ch_len);
+       gtk_text_iter_forward_char(&iter);
+       if (gtk_text_iter_ends_line(&iter))
+               return 0;
+       return len;
+}
 
-               /* fix line length for tabs */
-               if (ch_len == 1 && *cbuf == '\t') {
-                       guint tab_width = text->default_tab_width;
-                       guint tab_offset = line_len % tab_width;
+static gboolean compose_get_line_break_pos(GtkTextBuffer *buffer,
+                                          const GtkTextIter *start,
+                                          GtkTextIter *break_pos,
+                                          gint max_col,
+                                          gint quote_len)
+{
+       GtkTextIter iter = *start, line_end = *start;
+       PangoLogAttr *attrs;
+       gchar *str;
+       gchar *p;
+       gint len;
+       gint i;
+       gint col = 0;
+       gint pos = 0;
+       gboolean can_break = FALSE;
+       gboolean do_break = FALSE;
+       gboolean was_white = FALSE;
+       gboolean prev_dont_break = FALSE;
+
+       gtk_text_iter_forward_to_line_end(&line_end);
+       str = gtk_text_buffer_get_text(buffer, &iter, &line_end, FALSE);
+       len = g_utf8_strlen(str, -1);
+       
+       if (len == 0) {
+               g_free(str);
+               g_warning("compose_get_line_break_pos: len = 0!\n");
+               return FALSE;
+       }
 
-#ifdef WRAP_DEBUG
-                       g_print("found tab at pos=%d line_len=%d ", cur_pos,
-                               line_len);
-#endif
-                       if (tab_offset) {
-                               line_len += tab_width - tab_offset - 1;
-                               cur_len = line_len;
-                       }
-#ifdef WRAP_DEBUG
-                       printf("new_len=%d\n", line_len);
-#endif
-               }
+       /* g_print("breaking line: %d: %s (len = %d)\n",
+               gtk_text_iter_get_line(&iter), str, len); */
 
-               /* we have encountered line break */
-               if (ch_len == 1 && *cbuf == '\n') {
-                       gint clen;
-                       gchar cb[MB_LEN_MAX];
+       attrs = g_new(PangoLogAttr, len + 1);
 
-                       /* should we join the next line */
-                       if ((autowrap || i_len != cur_len) && do_delete &&
-                           join_next_line
-                               (text, cur_pos + 1, tlen, i_len, autowrap))
-                               do_delete = TRUE;
-                       else
-                               do_delete = FALSE;
+       pango_default_break(str, -1, NULL, attrs, len + 1);
 
-#ifdef WRAP_DEBUG
-                       g_print("found CR at %d do_del is %d next line is ",
-                              cur_pos, do_delete);
-                       dump_text(text, cur_pos + 1, tlen, 1);
-#endif
+       p = str;
 
-                       /* skip delete if it is continuous URL */
-                       if (do_delete && (line_pos - p_pos <= i_len) &&
-                           gtk_stext_is_uri_string(text, line_pos, tlen))
-                               do_delete = FALSE;
+       /* skip quote and leading spaces */
+       for (i = 0; *p != '\0' && i < len; i++) {
+               gunichar wc;
 
-#ifdef WRAP_DEBUG
-                       g_print("l_len=%d wrap_len=%d do_del=%d\n",
-                               line_len, linewrap_len, do_delete);
-#endif
-                       if (line_len < linewrap_len && do_delete) {
-                               STEXT_FREEZE();
-                               /* get rid of newline */
-                               gtk_stext_set_point(text, cur_pos);
-                               gtk_stext_forward_delete(text, 1);
-                               tlen--;
-
-                               /* if text starts with quote fmt or with
-                                  indent string, delete them */
-                               if (i_len) {
-                                       guint ilen;
-                                       ilen =  gtk_stext_str_compare_n
-                                               (text, cur_pos, p_pos, i_len,
-                                                tlen);
-                                       if (ilen) {
-                                               gtk_stext_forward_delete
-                                                       (text, ilen);
-                                               tlen -= ilen;
-                                       }
-                               }
+               wc = g_utf8_get_char(p);
+               if (i >= quote_len && !g_unichar_isspace(wc))
+                       break;
+               if (g_unichar_iswide(wc))
+                       col += 2;
+               else if (*p == '\t')
+                       col += 8;
+               else
+                       col++;
+               p = g_utf8_next_char(p);
+       }
 
-                               GET_CHAR(cur_pos, cb, clen);
-                               /* insert space between the next line */
-                               if (cur_pos > 0) {
-                                       gint clen_prev;
-                                       gchar cb_prev[MB_LEN_MAX];
-
-                                       GET_CHAR(cur_pos - 1, cb_prev,
-                                                clen_prev);
-                                       if ((clen_prev != clen && clen > 1) ||
-                                           (clen == 1 &&
-                                            !isspace((guchar)cb[0]))) {
-                                               gtk_stext_insert
-                                                       (text, NULL, NULL,
-                                                        NULL, " ", 1);
-                                               tlen++;
-                                       }
-                               }
+       for (; *p != '\0' && i < len; i++) {
+               PangoLogAttr *attr = attrs + i;
+               gunichar wc;
+               gint uri_len;
 
-                               /* and start over with current line */
-                               cur_pos = p_pos - 1;
-                               line_pos = cur_pos;
-                               line_len = cur_len = 0;
-                               do_delete = FALSE;
-                               is_new_line = TRUE;
-#ifdef WRAP_DEBUG
-                               g_print("after delete l_pos=");
-                               dump_text(text, line_pos, tlen, 1);
-#endif
-                               /* move beginning of line if we are on LF */
-                               GET_CHAR(line_pos, cb, clen);
-                               if (clen == 1 && *cb == '\n')
-                                       line_pos++;
-#ifdef WRAP_DEBUG
-                               g_print("new line_pos=%d\n", line_pos);
-#endif
+               if (attr->is_line_break && can_break && was_white && !prev_dont_break)
+                       pos = i;
+               
+               was_white = attr->is_white;
 
-                               continue;
+               /* don't wrap URI */
+               if ((uri_len = get_uri_len(p)) > 0) {
+                       col += uri_len;
+                       if (pos > 0 && col > max_col) {
+                               do_break = TRUE;
+                               break;
                        }
-
-                       /* mark new line beginning */
-                       line_pos = cur_pos + 1;
-                       line_len = cur_len = 0;
-                       do_delete = FALSE;
-                       is_new_line = TRUE;
+                       i += uri_len - 1;
+                       p += uri_len;
+                       can_break = TRUE;
                        continue;
                }
 
-               if (ch_len < 0) {
-                       cbuf[0] = '\0';
-                       ch_len = 1;
+               wc = g_utf8_get_char(p);
+               if (g_unichar_iswide(wc)) {
+                       col += 2;
+                       if (prev_dont_break && can_break && attr->is_line_break)
+                               pos = i;
+               } else if (*p == '\t')
+                       col += 8;
+               else
+                       col++;
+               if (pos > 0 && col > max_col) {
+                       do_break = TRUE;
+                       break;
                }
 
-               /* possible line break */
-               if (ch_len == 1 && isspace(*(guchar *)cbuf)) {
-                       line_pos = cur_pos + 1;
-                       line_len = cur_len + ch_len;
-               }
+               if (*p == '-' || *p == '/')
+                       prev_dont_break = TRUE;
+               else
+                       prev_dont_break = FALSE;
 
-               /* are we over wrapping length set in preferences ? */
-               if (cur_len + DISP_WIDTH(ch_len) > linewrap_len) {
-                       gint clen;
+               p = g_utf8_next_char(p);
+               can_break = TRUE;
+       }
 
-#ifdef WRAP_DEBUG
-                       g_print("should wrap cur_pos=%d ", cur_pos);
-                       dump_text(text, p_pos, tlen, 1);
-                       dump_text(text, line_pos, tlen, 1);
-#endif
-                       /* force wrapping if it is one long word but not URL */
-                       if (line_pos - p_pos <= i_len)
-                               if (!gtk_stext_is_uri_string
-                                   (text, line_pos, tlen))
-                                       line_pos = cur_pos - 1;
-#ifdef WRAP_DEBUG
-                       g_print("new line_pos=%d\n", line_pos);
-#endif
+//     debug_print("compose_get_line_break_pos(): do_break = %d, pos = %d, col = %d\n", do_break, pos, col);
 
-                       GET_CHAR(line_pos - 1, cbuf, clen);
-
-                       /* if next character is space delete it */
-                       if (clen == 1 && isspace(*(guchar *)cbuf)) {
-                               if (p_pos + i_len != line_pos ||
-                                   !gtk_stext_is_uri_string
-                                       (text, line_pos, tlen)) {
-                                       STEXT_FREEZE();
-                                       /* workaround for correct cursor
-                                          position */
-                                       if (set_editable_pos == FALSE) {
-                                               editable_pos = gtk_editable_get_position(GTK_EDITABLE(text));
-                                               if (editable_pos == line_pos)
-                                                       set_editable_pos = TRUE;
-                                       }
-                                       gtk_stext_set_point(text, line_pos);
-                                       gtk_stext_backward_delete(text, 1);
-                                       tlen--;
-                                       cur_pos--;
-                                       line_pos--;
-                                       cur_len--;
-                                       line_len--;
+       g_free(attrs);
+       g_free(str);
+
+       *break_pos = *start;
+       gtk_text_iter_set_line_offset(break_pos, pos);
+
+       return do_break;
+}
+
+static gboolean compose_join_next_line(Compose *compose,
+                                      GtkTextBuffer *buffer,
+                                      GtkTextIter *iter,
+                                      const gchar *quote_str)
+{
+       GtkTextIter iter_ = *iter, cur, prev, next, end;
+       PangoLogAttr attrs[3];
+       gchar *str;
+       gchar *next_quote_str;
+       gunichar wc1, wc2;
+       gint quote_len;
+       gboolean keep_cursor = FALSE;
+
+       if (!gtk_text_iter_forward_line(&iter_) ||
+           gtk_text_iter_ends_line(&iter_)) {
+               return FALSE;
+       }
+       next_quote_str = compose_get_quote_str(buffer, &iter_, &quote_len);
+
+       if ((quote_str || next_quote_str) &&
+           strcmp2(quote_str, next_quote_str) != 0) {
+               g_free(next_quote_str);
+               return FALSE;
+       }
+       g_free(next_quote_str);
+
+       end = iter_;
+       if (quote_len > 0) {
+               gtk_text_iter_forward_chars(&end, quote_len);
+               if (gtk_text_iter_ends_line(&end)) {
+                       return FALSE;
+               }
+       }
+
+       /* don't join itemized lines */
+       if (compose_itemized_length(buffer, &end) > 0) {
+               return FALSE;
+       }
+
+       /* don't join signature separator */
+       if (compose_is_sig_separator(compose, buffer, &iter_)) {
+               return FALSE;
+       }
+       /* delete quote str */
+       if (quote_len > 0)
+               gtk_text_buffer_delete(buffer, &iter_, &end);
+
+       /* don't join line breaks put by the user */
+       prev = cur = iter_;
+       gtk_text_iter_backward_char(&cur);
+       if (gtk_text_iter_has_tag(&cur, compose->no_join_tag)) {
+               gtk_text_iter_forward_char(&cur);
+               *iter = cur;
+               return FALSE;
+       }
+       gtk_text_iter_forward_char(&cur);
+       /* delete linebreak and extra spaces */
+       while (gtk_text_iter_backward_char(&cur)) {
+               wc1 = gtk_text_iter_get_char(&cur);
+               if (!g_unichar_isspace(wc1))
+                       break;
+               prev = cur;
+       }
+       next = cur = iter_;
+       while (!gtk_text_iter_ends_line(&cur)) {
+               wc1 = gtk_text_iter_get_char(&cur);
+               if (!g_unichar_isspace(wc1))
+                       break;
+               gtk_text_iter_forward_char(&cur);
+               next = cur;
+       }
+       if (!gtk_text_iter_equal(&prev, &next)) {
+               GtkTextMark *mark;
+
+               mark = gtk_text_buffer_get_insert(buffer);
+               gtk_text_buffer_get_iter_at_mark(buffer, &cur, mark);
+               if (gtk_text_iter_equal(&prev, &cur))
+                       keep_cursor = TRUE;
+               gtk_text_buffer_delete(buffer, &prev, &next);
+       }
+       iter_ = prev;
+
+       /* insert space if required */
+       gtk_text_iter_backward_char(&prev);
+       wc1 = gtk_text_iter_get_char(&prev);
+       wc2 = gtk_text_iter_get_char(&next);
+       gtk_text_iter_forward_char(&next);
+       str = gtk_text_buffer_get_text(buffer, &prev, &next, FALSE);
+       pango_default_break(str, -1, NULL, attrs, 3);
+       if (!attrs[1].is_line_break ||
+           (!g_unichar_iswide(wc1) || !g_unichar_iswide(wc2))) {
+               gtk_text_buffer_insert(buffer, &iter_, " ", 1);
+               if (keep_cursor) {
+                       gtk_text_iter_backward_char(&iter_);
+                       gtk_text_buffer_place_cursor(buffer, &iter_);
+               }
+       }
+       g_free(str);
+
+       *iter = iter_;
+       return TRUE;
+}
+
+#define ADD_TXT_POS(bp_, ep_, pti_) \
+       if ((last->next = alloca(sizeof(struct txtpos))) != NULL) { \
+               last = last->next; \
+               last->bp = (bp_); last->ep = (ep_); last->pti = (pti_); \
+               last->next = NULL; \
+       } else { \
+               g_warning("alloc error scanning URIs\n"); \
+       }
+
+static gboolean compose_beautify_paragraph(Compose *compose, GtkTextIter *par_iter, gboolean force)
+{
+       GtkTextView *text = GTK_TEXT_VIEW(compose->text);
+       GtkTextBuffer *buffer;
+       GtkTextIter iter, break_pos, end_of_line;
+       gchar *quote_str = NULL;
+       gint quote_len;
+       gboolean wrap_quote = prefs_common.linewrap_quote;
+       gboolean prev_autowrap = compose->autowrap;
+       gint startq_offset = -1, noq_offset = -1;
+       gint uri_start = -1, uri_stop = -1;
+       gint nouri_start = -1, nouri_stop = -1;
+       gint num_blocks = 0;
+       gint quotelevel = -1;
+       gboolean modified = force;
+       gboolean removed = FALSE;
+       gboolean modified_before_remove = FALSE;
+       gint lines = 0;
+       gboolean start = TRUE;
+       gint itemized_len = 0, rem_item_len = 0;
+       gchar *itemized_chars = NULL;
+       gboolean item_continuation = FALSE;
+
+       if (force) {
+               modified = TRUE;
+       }
+       if (compose->draft_timeout_tag == -2) {
+               modified = TRUE;
+       }
+
+       compose->autowrap = FALSE;
+
+       buffer = gtk_text_view_get_buffer(text);
+       undo_wrapping(compose->undostruct, TRUE);
+       if (par_iter) {
+               iter = *par_iter;
+       } else {
+               GtkTextMark *mark;
+               mark = gtk_text_buffer_get_insert(buffer);
+               gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
+       }
+
+
+       if (compose->draft_timeout_tag == -2) {
+               if (gtk_text_iter_ends_line(&iter)) {
+                       while (gtk_text_iter_ends_line(&iter) &&
+                              gtk_text_iter_forward_line(&iter))
+                               ;
+               } else {
+                       while (gtk_text_iter_backward_line(&iter)) {
+                               if (gtk_text_iter_ends_line(&iter)) {
+                                       gtk_text_iter_forward_line(&iter);
+                                       break;
                                }
                        }
+               }
+       } else {
+               /* move to line start */
+               gtk_text_iter_set_line_offset(&iter, 0);
+       }
+       
+       itemized_len = compose_itemized_length(buffer, &iter);
+       
+       if (!itemized_len) {
+               itemized_len = compose_left_offset_length(buffer, &iter);
+               item_continuation = TRUE;
+       }
+
+       if (itemized_len)
+               itemized_chars = compose_get_itemized_chars(buffer, &iter);
+
+       /* go until paragraph end (empty line) */
+       while (start || !gtk_text_iter_ends_line(&iter)) {
+               gchar *scanpos = NULL;
+               /* parse table - in order of priority */
+               struct table {
+                       const gchar *needle; /* token */
+
+                       /* token search function */
+                       gchar    *(*search)     (const gchar *haystack,
+                                                const gchar *needle);
+                       /* part parsing function */
+                       gboolean  (*parse)      (const gchar *start,
+                                                const gchar *scanpos,
+                                                const gchar **bp_,
+                                                const gchar **ep_,
+                                                gboolean hdr);
+                       /* part to URI function */
+                       gchar    *(*build_uri)  (const gchar *bp,
+                                                const gchar *ep);
+               };
+
+               static struct table parser[] = {
+                       {"http://",  strcasestr, get_uri_part,   make_uri_string},
+                       {"https://", strcasestr, get_uri_part,   make_uri_string},
+                       {"ftp://",   strcasestr, get_uri_part,   make_uri_string},
+                       {"sftp://",  strcasestr, get_uri_part,   make_uri_string},
+                       {"www.",     strcasestr, get_uri_part,   make_http_string},
+                       {"mailto:",  strcasestr, get_uri_part,   make_uri_string},
+                       {"@",        strcasestr, get_email_part, make_email_string}
+               };
+               const gint PARSE_ELEMS = sizeof parser / sizeof parser[0];
+               gint last_index = PARSE_ELEMS;
+               gint  n;
+               gchar *o_walk = NULL, *walk = NULL, *bp = NULL, *ep = NULL;
+               gint walk_pos;
+               
+               start = FALSE;
+               if (!prev_autowrap && num_blocks == 0) {
+                       num_blocks++;
+                       g_signal_handlers_block_by_func(G_OBJECT(buffer),
+                                       G_CALLBACK(text_inserted),
+                                       compose);
+               }
+               if (gtk_text_iter_has_tag(&iter, compose->no_wrap_tag) && !force)
+                       goto colorize;
+
+               uri_start = uri_stop = -1;
+               quote_len = 0;
+               quote_str = compose_get_quote_str(buffer, &iter, &quote_len);
+
+               if (quote_str) {
+//                     debug_print("compose_beautify_paragraph(): quote_str = '%s'\n", quote_str);
+                       if (startq_offset == -1) 
+                               startq_offset = gtk_text_iter_get_offset(&iter);
+                       quotelevel = get_quote_level(quote_str, prefs_common.quote_chars);
+                       if (quotelevel > 2) {
+                               /* recycle colors */
+                               if (prefs_common.recycle_quote_colors)
+                                       quotelevel %= 3;
+                               else
+                                       quotelevel = 2;
+                       }
+                       if (!wrap_quote) {
+                               goto colorize;
+                       }
+               } else {
+                       if (startq_offset == -1)
+                               noq_offset = gtk_text_iter_get_offset(&iter);
+                       quotelevel = -1;
+               }
 
-                       /* if it is URL at beginning of line don't wrap */
-                       if (p_pos + i_len == line_pos &&
-                           gtk_stext_is_uri_string(text, line_pos, tlen)) {
-#ifdef WRAP_DEBUG
-                               g_print("found URL at ");
-                               dump_text(text, line_pos, tlen, 1);
-#endif
-                               continue;
+               if (prev_autowrap == FALSE && !force && !wrap_quote) {
+                       goto colorize;
+               }
+               if (gtk_text_iter_ends_line(&iter)) {
+                       goto colorize;
+               } else if (compose_get_line_break_pos(buffer, &iter, &break_pos,
+                                              prefs_common.linewrap_len,
+                                              quote_len)) {
+                       GtkTextIter prev, next, cur;
+                       if (prev_autowrap != FALSE || force) {
+                               compose->automatic_break = TRUE;
+                               modified = TRUE;
+                               gtk_text_buffer_insert(buffer, &break_pos, "\n", 1);
+                               compose->automatic_break = FALSE;
+                               if (itemized_len && compose->autoindent) {
+                                       gtk_text_buffer_insert(buffer, &break_pos, itemized_chars, -1);
+                                       if (!item_continuation)
+                                               gtk_text_buffer_insert(buffer, &break_pos, "  ", 2);
+                               }
+                       } else if (quote_str && wrap_quote) {
+                               compose->automatic_break = TRUE;
+                               modified = TRUE;
+                               gtk_text_buffer_insert(buffer, &break_pos, "\n", 1);
+                               compose->automatic_break = FALSE;
+                               if (itemized_len && compose->autoindent) {
+                                       gtk_text_buffer_insert(buffer, &break_pos, itemized_chars, -1);
+                                       if (!item_continuation)
+                                               gtk_text_buffer_insert(buffer, &break_pos, "  ", 2);
+                               }
+                       } else 
+                               goto colorize;
+                       /* remove trailing spaces */
+                       cur = break_pos;
+                       rem_item_len = itemized_len;
+                       while (compose->autoindent && rem_item_len-- > 0)
+                               gtk_text_iter_backward_char(&cur);
+                       gtk_text_iter_backward_char(&cur);
+
+                       prev = next = cur;
+                       while (!gtk_text_iter_starts_line(&cur)) {
+                               gunichar wc;
+
+                               gtk_text_iter_backward_char(&cur);
+                               wc = gtk_text_iter_get_char(&cur);
+                               if (!g_unichar_isspace(wc))
+                                       break;
+                               prev = cur;
+                       }
+                       if (!gtk_text_iter_equal(&prev, &next)) {
+                               gtk_text_buffer_delete(buffer, &prev, &next);
+                               break_pos = next;
+                               gtk_text_iter_forward_char(&break_pos);
                        }
 
-                       /* insert CR */
-                       STEXT_FREEZE();
-                       gtk_stext_set_point(text, line_pos);
-                       gtk_stext_insert(text, NULL, NULL, NULL, "\n", 1);
-                       gtk_stext_compact_buffer(text);
-                       tlen++;
-                       line_pos++;
-                       /* for loop will increase it */
-                       cur_pos = line_pos - 1;
-                       /* start over with current line */
-                       is_new_line = TRUE;
-                       line_len = cur_len = 0;
-                       if (autowrap || i_len > 0)
-                               do_delete = TRUE;
-                       else
-                               do_delete = FALSE;
-#ifdef WRAP_DEBUG
-                       g_print("after CR insert ");
-                       dump_text(text, line_pos, tlen, 1);
-                       dump_text(text, cur_pos, tlen, 1);
-#endif
+                       if (quote_str)
+                               gtk_text_buffer_insert(buffer, &break_pos,
+                                                      quote_str, -1);
 
-                       /* should we insert quotation ? */
-                       if (linewrap_quote && i_len) {
-                               /* only if line is not already quoted  */
-                               if (!gtk_stext_str_compare
-                                       (text, line_pos, tlen, qfmt)) {
-                                       guint ins_len;
-
-                                       if (line_pos - p_pos > i_len) {
-                                               ins_len = ins_quote
-                                                       (text, i_len, p_pos,
-                                                        tlen, qfmt);
-                                               tlen += ins_len;
-                                       }
-#ifdef WRAP_DEBUG
-                                       g_print("after quote insert ");
-                                       dump_text(text, line_pos, tlen, 1);
-#endif
-                               }
+                       iter = break_pos;
+                       modified |= compose_join_next_line(compose, buffer, &iter, quote_str);
+
+                       /* move iter to current line start */
+                       gtk_text_iter_set_line_offset(&iter, 0);
+                       if (quote_str) {
+                               g_free(quote_str);
+                               quote_str = NULL;
                        }
-                       continue;
+                       continue;       
+               } else {
+                       /* move iter to next line start */
+                       iter = break_pos;
+                       lines++;
+               }
+
+colorize:
+               if (!prev_autowrap && num_blocks > 0) {
+                       num_blocks--;
+                       g_signal_handlers_unblock_by_func(G_OBJECT(buffer),
+                                       G_CALLBACK(text_inserted),
+                                       compose);
+               }
+               end_of_line = iter;
+               while (!gtk_text_iter_ends_line(&end_of_line)) {
+                       gtk_text_iter_forward_char(&end_of_line);
+               }
+               o_walk = walk = gtk_text_buffer_get_text(buffer, &iter, &end_of_line, FALSE);
+
+               nouri_start = gtk_text_iter_get_offset(&iter);
+               nouri_stop = gtk_text_iter_get_offset(&end_of_line);
+
+               walk_pos = gtk_text_iter_get_offset(&iter);
+               /* FIXME: this looks phony. scanning for anything in the parse table */
+               for (n = 0; n < PARSE_ELEMS; n++) {
+                       gchar *tmp;
+
+                       tmp = parser[n].search(walk, parser[n].needle);
+                       if (tmp) {
+                               if (scanpos == NULL || tmp < scanpos) {
+                                       scanpos = tmp;
+                                       last_index = n;
+                               }
+                       }                                       
                }
 
-               if (ch_len > 1) {
-                       line_pos = cur_pos + 1;
-                       line_len = cur_len + DISP_WIDTH(ch_len);
+               bp = ep = 0;
+               if (scanpos) {
+                       /* check if URI can be parsed */
+                       if (parser[last_index].parse(walk, scanpos, (const gchar **)&bp,
+                                       (const gchar **)&ep, FALSE)
+                           && (size_t) (ep - bp - 1) > strlen(parser[last_index].needle)) {
+                                       walk = ep;
+                       } else
+                               walk = scanpos +
+                                       strlen(parser[last_index].needle);
+               } 
+               if (bp && ep) {
+                       uri_start = walk_pos + (bp - o_walk);
+                       uri_stop  = walk_pos + (ep - o_walk);
+               }
+               g_free(o_walk);
+               o_walk = NULL;
+               gtk_text_iter_forward_line(&iter);
+               g_free(quote_str);
+               quote_str = NULL;
+               if (startq_offset != -1) {
+                       GtkTextIter startquote, endquote;
+                       gtk_text_buffer_get_iter_at_offset(
+                               buffer, &startquote, startq_offset);
+                       endquote = iter;
+
+                       switch (quotelevel) {
+                       case 0: 
+                               if (!gtk_text_iter_has_tag(&startquote, compose->quote0_tag) ||
+                                   !gtk_text_iter_has_tag(&end_of_line, compose->quote0_tag)) {
+                                       gtk_text_buffer_apply_tag_by_name(
+                                               buffer, "quote0", &startquote, &endquote);
+                                       gtk_text_buffer_remove_tag_by_name(
+                                               buffer, "quote1", &startquote, &endquote);
+                                       gtk_text_buffer_remove_tag_by_name(
+                                               buffer, "quote2", &startquote, &endquote);
+                                       modified = TRUE;
+                               }
+                               break;
+                       case 1: 
+                               if (!gtk_text_iter_has_tag(&startquote, compose->quote1_tag) ||
+                                   !gtk_text_iter_has_tag(&end_of_line, compose->quote1_tag)) {
+                                       gtk_text_buffer_apply_tag_by_name(
+                                               buffer, "quote1", &startquote, &endquote);
+                                       gtk_text_buffer_remove_tag_by_name(
+                                               buffer, "quote0", &startquote, &endquote);
+                                       gtk_text_buffer_remove_tag_by_name(
+                                               buffer, "quote2", &startquote, &endquote);
+                                       modified = TRUE;
+                               }
+                               break;
+                       case 2: 
+                               if (!gtk_text_iter_has_tag(&startquote, compose->quote2_tag) ||
+                                   !gtk_text_iter_has_tag(&end_of_line, compose->quote2_tag)) {
+                                       gtk_text_buffer_apply_tag_by_name(
+                                               buffer, "quote2", &startquote, &endquote);
+                                       gtk_text_buffer_remove_tag_by_name(
+                                               buffer, "quote0", &startquote, &endquote);
+                                       gtk_text_buffer_remove_tag_by_name(
+                                               buffer, "quote1", &startquote, &endquote);
+                                       modified = TRUE;
+                               }
+                               break;
+                       }
+                       startq_offset = -1;
+               } else if (noq_offset != -1) {
+                       GtkTextIter startnoquote, endnoquote;
+                       gtk_text_buffer_get_iter_at_offset(
+                               buffer, &startnoquote, noq_offset);
+                       endnoquote = iter;
+
+                       if ((gtk_text_iter_has_tag(&startnoquote, compose->quote0_tag)
+                         && gtk_text_iter_has_tag(&end_of_line, compose->quote0_tag)) ||
+                           (gtk_text_iter_has_tag(&startnoquote, compose->quote1_tag)
+                         && gtk_text_iter_has_tag(&end_of_line, compose->quote1_tag)) ||
+                           (gtk_text_iter_has_tag(&startnoquote, compose->quote2_tag)
+                         && gtk_text_iter_has_tag(&end_of_line, compose->quote2_tag))) {
+                               gtk_text_buffer_remove_tag_by_name(
+                                       buffer, "quote0", &startnoquote, &endnoquote);
+                               gtk_text_buffer_remove_tag_by_name(
+                                       buffer, "quote1", &startnoquote, &endnoquote);
+                               gtk_text_buffer_remove_tag_by_name(
+                                       buffer, "quote2", &startnoquote, &endnoquote);
+                               modified = TRUE;
+                       }
+                       noq_offset = -1;
+               }
+               
+               if (uri_start != nouri_start && uri_stop != nouri_stop) {
+                       GtkTextIter nouri_start_iter, nouri_end_iter;
+                       gtk_text_buffer_get_iter_at_offset(
+                               buffer, &nouri_start_iter, nouri_start);
+                       gtk_text_buffer_get_iter_at_offset(
+                               buffer, &nouri_end_iter, nouri_stop);
+                       if (gtk_text_iter_has_tag(&nouri_start_iter, compose->uri_tag) &&
+                           gtk_text_iter_has_tag(&nouri_end_iter, compose->uri_tag)) {
+                               gtk_text_buffer_remove_tag_by_name(
+                                       buffer, "link", &nouri_start_iter, &nouri_end_iter);
+                               modified_before_remove = modified;
+                               modified = TRUE;
+                               removed = TRUE;
+                       }
+               }
+               if (uri_start >= 0 && uri_stop > 0) {
+                       GtkTextIter uri_start_iter, uri_end_iter, back;
+                       gtk_text_buffer_get_iter_at_offset(
+                               buffer, &uri_start_iter, uri_start);
+                       gtk_text_buffer_get_iter_at_offset(
+                               buffer, &uri_end_iter, uri_stop);
+                       back = uri_end_iter;
+                       gtk_text_iter_backward_char(&back);
+                       if (!gtk_text_iter_has_tag(&uri_start_iter, compose->uri_tag) ||
+                           !gtk_text_iter_has_tag(&back, compose->uri_tag)) {
+                               gtk_text_buffer_apply_tag_by_name(
+                                       buffer, "link", &uri_start_iter, &uri_end_iter);
+                               modified = TRUE;
+                               if (removed && !modified_before_remove) {
+                                       modified = FALSE;
+                               } 
+                       }
+               }
+               if (!modified) {
+//                     debug_print("not modified, out after %d lines\n", lines);
+                       goto end;
                }
-               /* advance to next character in buffer */
-               cur_len += DISP_WIDTH(ch_len);
        }
+//     debug_print("modified, out after %d lines\n", lines);
+end:
+       g_free(itemized_chars);
+       if (par_iter)
+               *par_iter = iter;
+       undo_wrapping(compose->undostruct, FALSE);
+       compose->autowrap = prev_autowrap;
+       
+       return modified;
+}
 
-       if (frozen)
-               gtk_stext_thaw(text);
+void compose_action_cb(void *data)
+{
+       Compose *compose = (Compose *)data;
+       compose_wrap_all(compose);
+}
 
-       if (set_editable_pos && editable_pos <= tlen)
-               gtk_editable_set_position(GTK_EDITABLE(text), editable_pos);
+static void compose_wrap_all(Compose *compose)
+{
+       compose_wrap_all_full(compose, FALSE);
 }
 
-#undef STEXT_FREEZE
-#undef GET_CHAR
+static void compose_wrap_all_full(Compose *compose, gboolean force)
+{
+       GtkTextView *text = GTK_TEXT_VIEW(compose->text);
+       GtkTextBuffer *buffer;
+       GtkTextIter iter;
+       gboolean modified = TRUE;
+
+       buffer = gtk_text_view_get_buffer(text);
+
+       gtk_text_buffer_get_start_iter(buffer, &iter);
+       while (!gtk_text_iter_is_end(&iter) && modified)
+               modified = compose_beautify_paragraph(compose, &iter, force);
+
+}
 
 static void compose_set_title(Compose *compose)
 {
        gchar *str;
        gchar *edited;
-
+       gchar *subject;
+       
        edited = compose->modified ? _(" [Edited]") : "";
-       if (compose->account && compose->account->address)
+       
+       subject = gtk_editable_get_chars(
+                       GTK_EDITABLE(compose->subject_entry), 0, -1);
+
+#ifndef GENERIC_UMPC
+       if (subject && strlen(subject))
                str = g_strdup_printf(_("%s - Compose message%s"),
-                                     compose->account->address, edited);
+                                     subject, edited); 
        else
-               str = g_strdup_printf(_("Compose message%s"), edited);
+               str = g_strdup_printf(_("[no subject] - Compose message%s"), edited);
+#else
+       str = g_strdup(_("Compose message"));
+#endif
+
        gtk_window_set_title(GTK_WINDOW(compose->window), str);
        g_free(str);
+       g_free(subject);
 }
 
 /**
@@ -2988,79 +4461,116 @@ compose_current_mail_account(void)
        return ac;
 }
 
+#define QUOTE_IF_REQUIRED(out, str)                                    \
+{                                                                      \
+       if (*str != '"' && strpbrk(str, ",.[]<>")) {                    \
+               gchar *__tmp;                                           \
+               gint len;                                               \
+                                                                       \
+               len = strlen(str) + 3;                                  \
+               if ((__tmp = alloca(len)) == NULL) {                    \
+                       g_warning("can't allocate memory\n");           \
+                       g_string_free(header, TRUE);                    \
+                       return NULL;                                    \
+               }                                                       \
+               g_snprintf(__tmp, len, "\"%s\"", str);                  \
+               out = __tmp;                                            \
+       } else {                                                        \
+               gchar *__tmp;                                           \
+                                                                       \
+               if ((__tmp = alloca(strlen(str) + 1)) == NULL) {        \
+                       g_warning("can't allocate memory\n");           \
+                       g_string_free(header, TRUE);                    \
+                       return NULL;                                    \
+               } else                                                  \
+                       strcpy(__tmp, str);                             \
+                                                                       \
+               out = __tmp;                                            \
+       }                                                               \
+}
+
+#define QUOTE_IF_REQUIRED_NORMAL(out, str, errret)                     \
+{                                                                      \
+       if (*str != '"' && strpbrk(str, ",.[]<>")) {                    \
+               gchar *__tmp;                                           \
+               gint len;                                               \
+                                                                       \
+               len = strlen(str) + 3;                                  \
+               if ((__tmp = alloca(len)) == NULL) {                    \
+                       g_warning("can't allocate memory\n");           \
+                       errret;                                         \
+               }                                                       \
+               g_snprintf(__tmp, len, "\"%s\"", str);                  \
+               out = __tmp;                                            \
+       } else {                                                        \
+               gchar *__tmp;                                           \
+                                                                       \
+               if ((__tmp = alloca(strlen(str) + 1)) == NULL) {        \
+                       g_warning("can't allocate memory\n");           \
+                       errret;                                         \
+               } else                                                  \
+                       strcpy(__tmp, str);                             \
+                                                                       \
+               out = __tmp;                                            \
+       }                                                               \
+}
+
 static void compose_select_account(Compose *compose, PrefsAccount *account,
                                   gboolean init)
 {
-       GtkItemFactory *ifactory;
+       gchar *from = NULL;
 
-       g_return_if_fail(account != NULL);
+       cm_return_if_fail(account != NULL);
 
        compose->account = account;
 
-       compose_set_title(compose);
-
-       ifactory = gtk_item_factory_from_widget(compose->menubar);
-#if 0
-       if (account->protocol == A_NNTP) {
-               gtk_widget_show(compose->newsgroups_hbox);
-               gtk_widget_show(compose->newsgroups_entry);
-               gtk_table_set_row_spacing(GTK_TABLE(compose->table), 2, 4);
-               compose->use_newsgroups = TRUE;
-
-               menu_set_active(ifactory, "/View/To", FALSE);
-               menu_set_sensitive(ifactory, "/View/To", TRUE);
-               menu_set_active(ifactory, "/View/Cc", FALSE);
-               menu_set_sensitive(ifactory, "/View/Cc", TRUE);
-               menu_set_sensitive(ifactory, "/View/Followup to", TRUE);
+       if (account->name && *account->name) {
+               gchar *buf;
+               QUOTE_IF_REQUIRED_NORMAL(buf, account->name, return);
+               from = g_strdup_printf("%s <%s>",
+                                      buf, account->address);
+               gtk_entry_set_text(GTK_ENTRY(compose->from_name), from);
        } else {
-               gtk_widget_hide(compose->newsgroups_hbox);
-               gtk_widget_hide(compose->newsgroups_entry);
-               gtk_table_set_row_spacing(GTK_TABLE(compose->table), 2, 0);
-               gtk_widget_queue_resize(compose->table_vbox);
-               compose->use_newsgroups = FALSE;
-
-               menu_set_active(ifactory, "/View/To", TRUE);
-               menu_set_sensitive(ifactory, "/View/To", FALSE);
-               menu_set_active(ifactory, "/View/Cc", TRUE);
-               menu_set_sensitive(ifactory, "/View/Cc", FALSE);
-               menu_set_active(ifactory, "/View/Followup to", FALSE);
-               menu_set_sensitive(ifactory, "/View/Followup to", FALSE);
-       }
-
-       if (account->set_autocc) {
-               compose_entry_show(compose, COMPOSE_ENTRY_CC);
-               if (account->auto_cc && compose->mode != COMPOSE_REEDIT)
-                       compose_entry_set(compose, account->auto_cc,
-                                         COMPOSE_ENTRY_CC);
-       }
-       if (account->set_autobcc) {
-               compose_entry_show(compose, COMPOSE_ENTRY_BCC);
-               if (account->auto_bcc && compose->mode != COMPOSE_REEDIT)
-                       compose_entry_set(compose, account->auto_bcc,
-                                         COMPOSE_ENTRY_BCC);
-       }
-       if (account->set_autoreplyto) {
-               compose_entry_show(compose, COMPOSE_ENTRY_REPLY_TO);
-               if (account->auto_replyto && compose->mode != COMPOSE_REEDIT)
-                       compose_entry_set(compose, account->auto_replyto,
-                                         COMPOSE_ENTRY_REPLY_TO);
+               from = g_strdup_printf("<%s>",
+                                      account->address);
+               gtk_entry_set_text(GTK_ENTRY(compose->from_name), from);
        }
 
-#endif
+       g_free(from);
+
+       compose_set_title(compose);
 
        if (account->default_sign && compose->mode != COMPOSE_REDIRECT)
-               menu_set_active(ifactory, "/Options/Sign", TRUE);
+               cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/Sign", TRUE);
        else
-               menu_set_active(ifactory, "/Options/Sign", FALSE);
+               cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/Sign", FALSE);
        if (account->default_encrypt && compose->mode != COMPOSE_REDIRECT)
-               menu_set_active(ifactory, "/Options/Encrypt", TRUE);
+               cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/Encrypt", TRUE);
        else
-               menu_set_active(ifactory, "/Options/Encrypt", FALSE);
+               cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Options/Encrypt", FALSE);
                                       
-       activate_privacy_system(compose, account);
+       activate_privacy_system(compose, account, FALSE);
 
-       if (!init && compose->mode != COMPOSE_REDIRECT)
+       if (!init && compose->mode != COMPOSE_REDIRECT) {
+               undo_block(compose->undostruct);
                compose_insert_sig(compose, TRUE);
+               undo_unblock(compose->undostruct);
+       }
+
+#ifdef USE_ENCHANT
+       /* use account's dict info if set */
+       if (compose->gtkaspell) {
+               if (account->enable_default_dictionary)
+                       gtkaspell_change_dict(compose->gtkaspell,
+                                       account->default_dictionary, FALSE);
+               if (account->enable_default_alt_dictionary)
+                       gtkaspell_change_alt_dict(compose->gtkaspell,
+                                       account->default_alt_dictionary);
+               if (account->enable_default_dictionary
+                       || account->enable_default_alt_dictionary)
+                       compose_spell_menu_changed(compose);
+       }
+#endif
 }
 
 gboolean compose_check_for_valid_recipient(Compose *compose) {
@@ -3083,18 +4593,19 @@ gboolean compose_check_for_valid_recipient(Compose *compose) {
        for (list = compose->header_list; list; list = list->next) {
                gchar *header;
                gchar *entry;
-               header = gtk_editable_get_chars(GTK_EDITABLE(GTK_COMBO(((ComposeHeaderEntry *)list->data)->combo)->entry), 0, -1);
+               header = gtk_editable_get_chars(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN((((ComposeHeaderEntry *)list->data)->combo)))), 0, -1);
                entry = gtk_editable_get_chars(GTK_EDITABLE(((ComposeHeaderEntry *)list->data)->entry), 0, -1);
                g_strstrip(entry);
+               g_strstrip(header);
                if (entry[0] != '\0') {
                        for (strptr = recipient_headers_mail; *strptr != NULL; strptr++) {
-                               if (!strcmp(header, (prefs_common.trans_hdr ? gettext(*strptr) : *strptr))) {
+                               if (!strcmp(header, prefs_common_translated_header_name(*strptr))) {
                                        compose->to_list = address_list_append(compose->to_list, entry);
                                        recipient_found = TRUE;
                                }
                        }
                        for (strptr = recipient_headers_news; *strptr != NULL; strptr++) {
-                               if (!strcmp(header, (prefs_common.trans_hdr ? gettext(*strptr) : *strptr))) {
+                               if (!strcmp(header, prefs_common_translated_header_name(*strptr))) {
                                        compose->newsgroup_list = newsgroup_list_append(compose->newsgroup_list, entry);
                                        recipient_found = TRUE;
                                }
@@ -3106,109 +4617,278 @@ gboolean compose_check_for_valid_recipient(Compose *compose) {
        return recipient_found;
 }
 
-static gboolean compose_check_entries(Compose *compose, gboolean check_subject)
+static gboolean compose_check_for_set_recipients(Compose *compose)
+{
+       if (compose->account->set_autocc && compose->account->auto_cc) {
+               gboolean found_other = FALSE;
+               GSList *list;
+               /* search header entries for to and newsgroup entries */
+               for (list = compose->header_list; list; list = list->next) {
+                       gchar *entry;
+                       gchar *header;
+                       entry = gtk_editable_get_chars(GTK_EDITABLE(((ComposeHeaderEntry *)list->data)->entry), 0, -1);
+                       header = gtk_editable_get_chars(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN((((ComposeHeaderEntry *)list->data)->combo)))), 0, -1);
+                       g_strstrip(entry);
+                       g_strstrip(header);
+                       if (strcmp(entry, compose->account->auto_cc)
+                       ||  strcmp(header, prefs_common_translated_header_name("Cc:"))) {
+                               found_other = TRUE;
+                               g_free(entry);
+                               break;
+                       }
+                       g_free(entry);
+                       g_free(header);
+               }
+               if (!found_other) {
+                       AlertValue aval;
+                       if (compose->batch) {
+                               gtk_widget_show_all(compose->window);
+                       }
+                       aval = alertpanel(_("Send"),
+                                         _("The only recipient is the default CC address. Send anyway?"),
+                                         GTK_STOCK_CANCEL, _("+_Send"), NULL);
+                       if (aval != G_ALERTALTERNATE)
+                               return FALSE;
+               }
+       }
+       if (compose->account->set_autobcc && compose->account->auto_bcc) {
+               gboolean found_other = FALSE;
+               GSList *list;
+               /* search header entries for to and newsgroup entries */
+               for (list = compose->header_list; list; list = list->next) {
+                       gchar *entry;
+                       gchar *header;
+                       entry = gtk_editable_get_chars(GTK_EDITABLE(((ComposeHeaderEntry *)list->data)->entry), 0, -1);
+                       header = gtk_editable_get_chars(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN((((ComposeHeaderEntry *)list->data)->combo)))), 0, -1);
+                       g_strstrip(entry);
+                       g_strstrip(header);
+                       if (strcmp(entry, compose->account->auto_bcc)
+                       ||  strcmp(header, prefs_common_translated_header_name("Bcc:"))) {
+                               found_other = TRUE;
+                               g_free(entry);
+                               break;
+                       }
+                       g_free(entry);
+                       g_free(header);
+               }
+               if (!found_other) {
+                       AlertValue aval;
+                       if (compose->batch) {
+                               gtk_widget_show_all(compose->window);
+                       }
+                       aval = alertpanel(_("Send"),
+                                         _("The only recipient is the default BCC address. Send anyway?"),
+                                         GTK_STOCK_CANCEL, _("+_Send"), NULL);
+                       if (aval != G_ALERTALTERNATE)
+                               return FALSE;
+               }
+       }
+       return TRUE;
+}
+
+static gboolean compose_check_entries(Compose *compose, gboolean check_everything)
 {
-       gchar *str;
+       const gchar *str;
 
        if (compose_check_for_valid_recipient(compose) == FALSE) {
+               if (compose->batch) {
+                       gtk_widget_show_all(compose->window);
+               }
                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;
+       if (compose_check_for_set_recipients(compose) == FALSE) {
+               return FALSE;
+       }
 
-               aval = alertpanel(_("Send"),
-                                 _("Subject is empty. Send it anyway?"),
-                                 _("Yes"), _("No"), NULL);
-               if (aval != G_ALERTDEFAULT)
-                       return FALSE;
+       if (!compose->batch) {
+               str = gtk_entry_get_text(GTK_ENTRY(compose->subject_entry));
+               if (*str == '\0' && check_everything == TRUE && 
+                   compose->mode != COMPOSE_REDIRECT) {
+                       AlertValue aval;
+                       gchar *button_label;
+                       gchar *message;
+
+                       if (compose->sending)
+                               button_label = _("+_Send");
+                       else
+                               button_label = _("+_Queue");
+                       message = g_strdup_printf(_("Subject is empty. %s"),
+                                       compose->sending?_("Send it anyway?"):
+                                       _("Queue it anyway?"));
+
+                       aval = alertpanel(compose->sending?_("Send"):_("Send later"), message,
+                                         GTK_STOCK_CANCEL, button_label, NULL);
+                       g_free(message);
+                       if (aval != G_ALERTALTERNATE)
+                               return FALSE;
+               }
        }
 
+       if (check_everything && hooks_invoke(COMPOSE_CHECK_BEFORE_SEND_HOOKLIST, compose))
+               return FALSE;
+
        return TRUE;
 }
 
 gint compose_send(Compose *compose)
 {
        gint msgnum;
-       FolderItem *folder;
+       FolderItem *folder = NULL;
        gint val = -1;
-       gchar *msgpath;
+       gchar *msgpath = NULL;
+       gboolean discard_window = FALSE;
+       gchar *errstr = NULL;
+       gchar *tmsgid = NULL;
+       MainWindow *mainwin = mainwindow_get_mainwindow();
+       gboolean queued_removed = FALSE;
+
+       if (prefs_common.send_dialog_invisible
+                       || compose->batch == TRUE)
+               discard_window = TRUE;
 
        compose_allow_user_actions (compose, FALSE);
        compose->sending = TRUE;
 
-       if (compose_check_entries(compose, TRUE) == FALSE)
+       if (compose_check_entries(compose, TRUE) == FALSE) {
+               if (compose->batch) {
+                       gtk_widget_show_all(compose->window);
+               }
                goto bail;
+       }
 
-       val = compose_queue(compose, &msgnum, &folder);
+       inc_lock();
+       val = compose_queue(compose, &msgnum, &folder, &msgpath, TRUE);
 
        if (val) {
-               alertpanel_error(_("Could not queue message for sending"));
+               if (compose->batch) {
+                       gtk_widget_show_all(compose->window);
+               }
+               if (val == -4) {
+                       alertpanel_error(_("Could not queue message for sending:\n\n"
+                                          "Charset conversion failed."));
+               } else if (val == -5) {
+                       alertpanel_error(_("Could not queue message for sending:\n\n"
+                                          "Couldn't get recipient encryption key."));
+               } else if (val == -6) {
+                       /* silent error */
+               } else if (val == -3) {
+                       if (privacy_peek_error())
+                       alertpanel_error(_("Could not queue message for sending:\n\n"
+                                          "Signature failed: %s"), privacy_get_error());
+               } else if (val == -2 && errno != 0) {
+                       alertpanel_error(_("Could not queue message for sending:\n\n%s."), strerror(errno));
+               } else {
+                       alertpanel_error(_("Could not queue message for sending."));
+               }
                goto bail;
        }
 
-
-       if (prefs_common.send_dialog_mode != SEND_DIALOG_ALWAYS) {
+       tmsgid = compose->msgid ? g_strdup(compose->msgid) : NULL;
+       if (discard_window) {
                compose->sending = FALSE;
                compose_close(compose);
                /* No more compose access in the normal codepath 
                 * after this point! */
+               compose = NULL;
        }
 
        if (msgnum == 0) {
                alertpanel_error(_("The message was queued but could not be "
                                   "sent.\nUse \"Send queued messages\" from "
                                   "the main window to retry."));
-               if (prefs_common.send_dialog_mode == SEND_DIALOG_ALWAYS) {
-                       compose->sending = FALSE;
-                       compose_allow_user_actions (compose, TRUE);
+               if (!discard_window) {
+                       goto bail;
                }
-               return 0;
+               inc_unlock();
+               g_free(tmsgid);
+               return -1;
        }
-       
-       msgpath = folder_item_fetch_msg(folder, msgnum);
-       val = procmsg_send_message_queue(msgpath);
-       g_free(msgpath);
-
-       if (prefs_common.send_dialog_mode == SEND_DIALOG_ALWAYS) {
-               compose->sending = FALSE;
-               compose_allow_user_actions (compose, TRUE);
+       if (msgpath == NULL) {
+               msgpath = folder_item_fetch_msg(folder, msgnum);
+               val = procmsg_send_message_queue(msgpath, &errstr, folder, msgnum, &queued_removed);
+               g_free(msgpath);
+       } else {
+               val = procmsg_send_message_queue(msgpath, &errstr, folder, msgnum, &queued_removed);
+               claws_unlink(msgpath);
+               g_free(msgpath);
+       }
+       if (!discard_window) {
                if (val != 0) {
-                       folder_item_remove_msg(folder, msgnum);
+                       if (!queued_removed)
+                               folder_item_remove_msg(folder, msgnum);
                        folder_item_scan(folder);
+                       if (tmsgid) {
+                               /* make sure we delete that */
+                               MsgInfo *tmp = folder_item_get_msginfo_by_msgid(folder, tmsgid);
+                               if (tmp) {
+                                       debug_print("removing %d via %s\n", tmp->msgnum, tmsgid);
+                                       folder_item_remove_msg(folder, tmp->msgnum);
+                                       procmsg_msginfo_free(tmp);
+                               } 
+                       }
                }
        }
 
        if (val == 0) {
-               folder_item_remove_msg(folder, msgnum);
+               if (!queued_removed)
+                       folder_item_remove_msg(folder, msgnum);
                folder_item_scan(folder);
-               if (prefs_common.send_dialog_mode == SEND_DIALOG_ALWAYS)
+               if (tmsgid) {
+                       /* make sure we delete that */
+                       MsgInfo *tmp = folder_item_get_msginfo_by_msgid(folder, tmsgid);
+                       if (tmp) {
+                               debug_print("removing %d via %s\n", tmp->msgnum, tmsgid);
+                               folder_item_remove_msg(folder, tmp->msgnum);
+                               procmsg_msginfo_free(tmp);
+                       }
+               }
+               if (!discard_window) {
+                       compose->sending = FALSE;
+                       compose_allow_user_actions (compose, TRUE);
                        compose_close(compose);
+               }
        } else {
-               alertpanel_error(_("The message was queued but could not be "
+               if (errstr) {
+                       alertpanel_error_log(_("%s\nUse \"Send queued messages\" from "
+                                  "the main window to retry."), errstr);
+                       g_free(errstr);
+               } else {
+                       alertpanel_error_log(_("The message was queued but could not be "
                                   "sent.\nUse \"Send queued messages\" from "
                                   "the main window to retry."));
-               if (prefs_common.send_dialog_mode == SEND_DIALOG_ALWAYS) {
-                       compose_allow_user_actions (compose, TRUE);
-                       compose->sending = FALSE;               
                }
+               if (!discard_window) {
+                       goto bail;              
+               }
+               inc_unlock();
+               g_free(tmsgid);
                return -1;
        }
-
+       g_free(tmsgid);
+       inc_unlock();
+       toolbar_main_set_sensitive(mainwin);
+       main_window_set_menu_sensitive(mainwin);
        return 0;
 
 bail:
+       inc_unlock();
+       g_free(tmsgid);
        compose_allow_user_actions (compose, TRUE);
        compose->sending = FALSE;
+       compose->modified = TRUE; 
+       toolbar_main_set_sensitive(mainwin);
+       main_window_set_menu_sensitive(mainwin);
 
        return -1;
 }
 
 static gboolean compose_use_attach(Compose *compose) 
 {
-       return gtk_clist_get_row_data(GTK_CLIST(compose->attach_clist), 0) != NULL;
+       GtkTreeModel *model = gtk_tree_view_get_model
+                               (GTK_TREE_VIEW(compose->attach_clist));
+       return gtk_tree_model_iter_n_children(model, NULL) > 0;
 }
 
 static gint compose_redirect_write_headers_from_headerlist(Compose *compose, 
@@ -3220,123 +4900,140 @@ static gint compose_redirect_write_headers_from_headerlist(Compose *compose,
        gboolean first_cc_address;
        GSList *list;
        ComposeHeaderEntry *headerentry;
-       gchar *headerentryname;
-       gchar *cc_hdr;
-       gchar *to_hdr;
+       const gchar *headerentryname;
+       const gchar *cc_hdr;
+       const gchar *to_hdr;
+       gboolean err = FALSE;
 
        debug_print("Writing redirect header\n");
 
-       cc_hdr = prefs_common.trans_hdr ? _("Cc:") : "Cc:";
-       to_hdr = prefs_common.trans_hdr ? _("To:") : "To:";
+       cc_hdr = prefs_common_translated_header_name("Cc:");
+       to_hdr = prefs_common_translated_header_name("To:");
 
        first_to_address = TRUE;
        for (list = compose->header_list; list; list = list->next) {
                headerentry = ((ComposeHeaderEntry *)list->data);
-               headerentryname = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(headerentry->combo)->entry));
+               headerentryname = gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN((headerentry->combo)))));
 
-               if (g_strcasecmp(headerentryname, to_hdr) == 0) {
-                       str = gtk_entry_get_text(GTK_ENTRY(headerentry->entry));
-                       Xstrdup_a(str, str, return -1);
+               if (g_utf8_collate(headerentryname, to_hdr) == 0) {
+                       const gchar *entstr = gtk_entry_get_text(GTK_ENTRY(headerentry->entry));
+                       Xstrdup_a(str, entstr, return -1);
                        g_strstrip(str);
                        if (str[0] != '\0') {
                                compose_convert_header
-                                       (buf, sizeof(buf), str,
+                                       (compose, buf, sizeof(buf), str,
                                        strlen("Resent-To") + 2, TRUE);
 
-                                if (first_to_address) {
-                                        fprintf(fp, "Resent-To: ");
-                                        first_to_address = FALSE;
-                                } else {
-                                        fprintf(fp, ",");
+                               if (first_to_address) {
+                                       err |= (fprintf(fp, "Resent-To: ") < 0);
+                                       first_to_address = FALSE;
+                               } else {
+                                       err |= (fprintf(fp, ",") < 0);
                                 }
-                               fprintf(fp, "%s", buf);
+                               err |= (fprintf(fp, "%s", buf) < 0);
                        }
                }
        }
        if (!first_to_address) {
-               fprintf(fp, "\n");
-        }
+               err |= (fprintf(fp, "\n") < 0);
+       }
 
        first_cc_address = TRUE;
        for (list = compose->header_list; list; list = list->next) {
                headerentry = ((ComposeHeaderEntry *)list->data);
-               headerentryname = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(headerentry->combo)->entry));
+               headerentryname = gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN((headerentry->combo)))));
 
-               if (g_strcasecmp(headerentryname, cc_hdr) == 0) {
-                       str = gtk_entry_get_text(GTK_ENTRY(headerentry->entry));
-                       Xstrdup_a(str, str, return -1);
+               if (g_utf8_collate(headerentryname, cc_hdr) == 0) {
+                       const gchar *strg = gtk_entry_get_text(GTK_ENTRY(headerentry->entry));
+                       Xstrdup_a(str, strg, return -1);
                        g_strstrip(str);
                        if (str[0] != '\0') {
                                compose_convert_header
-                                       (buf, sizeof(buf), str,
+                                       (compose, buf, sizeof(buf), str,
                                        strlen("Resent-Cc") + 2, TRUE);
 
                                 if (first_cc_address) {
-                                        fprintf(fp, "Resent-Cc: ");
+                                        err |= (fprintf(fp, "Resent-Cc: ") < 0);
                                         first_cc_address = FALSE;
                                 } else {
-                                        fprintf(fp, ",");
+                                        err |= (fprintf(fp, ",") < 0);
                                 }
-     &