add check for '.' to QUOTE_IF_REQUIRED
[claws.git] / src / compose.c
index 96293c1944a2a7163d3b7cdc87b4cf92077eb9ba..7b106fa5358e1880448f51f1950d9f259a052f56 100644 (file)
@@ -84,6 +84,7 @@
 #include "customheader.h"
 #include "prefs_common.h"
 #include "prefs_account.h"
+#include "prefs_actions.h"
 #include "account.h"
 #include "filesel.h"
 #include "procheader.h"
 #include "template.h"
 #include "undo.h"
 #include "foldersel.h"
-#include "prefs_actions.h"
 
 #if USE_GPGME
 #  include "rfc2015.h"
@@ -138,6 +138,15 @@ typedef enum
        COMPOSE_CALL_GTK_STEXT_DELETE_TO_LINE_END
 } ComposeCallGtkSTextAction;
 
+typedef enum
+{
+       PRIORITY_HIGHEST = 1,
+       PRIORITY_HIGH,
+       PRIORITY_NORMAL,
+       PRIORITY_LOW,
+       PRIORITY_LOWEST
+} PriorityLevel;
+
 #define B64_LINE_SIZE          57
 #define B64_BUFFSIZE           77
 
@@ -149,7 +158,8 @@ static GList *compose_list = NULL;
 
 Compose *compose_generic_new                   (PrefsAccount   *account,
                                                 const gchar    *to,
-                                                FolderItem     *item);
+                                                FolderItem     *item,
+                                                GPtrArray      *attach_files);
 
 static Compose *compose_create                 (PrefsAccount   *account,
                                                 ComposeMode     mode);
@@ -159,7 +169,8 @@ static GtkWidget *compose_account_option_menu_create
                                                (Compose        *compose);
 static void compose_set_template_menu          (Compose        *compose);
 static void compose_template_apply             (Compose        *compose,
-                                                Template       *tmpl);
+                                                Template       *tmpl,
+                                                gboolean        replace);
 static void compose_destroy                    (Compose        *compose);
 
 static void compose_entries_set                        (Compose        *compose,
@@ -188,28 +199,33 @@ static void compose_insert_file                   (Compose        *compose,
                                                 const gchar    *file);
 static void compose_attach_append              (Compose        *compose,
                                                 const gchar    *file,
-                                                ContentType     cnttype);
-static void compose_attach_append_with_type(Compose *compose,
-                                           const gchar *file,
-                                           const gchar *type,
-                                           ContentType cnttype);
+                                                const gchar    *type,
+                                                const gchar    *content_type);
+static void compose_attach_parts               (Compose        *compose,
+                                                MsgInfo        *msginfo);
 static void compose_wrap_line                  (Compose        *compose);
 static void compose_wrap_line_all              (Compose        *compose);
 static void compose_set_title                  (Compose        *compose);
 
 static PrefsAccount *compose_current_mail_account(void);
 /* static gint compose_send                    (Compose        *compose); */
+static gboolean compose_check_for_valid_recipient
+                                               (Compose        *compose);
+static gboolean compose_check_entries          (Compose        *compose,
+                                                gboolean       check_subject);
 static gint compose_write_to_file              (Compose        *compose,
                                                 const gchar    *file,
                                                 gboolean        is_draft);
 static gint compose_write_body_to_file         (Compose        *compose,
                                                 const gchar    *file);
-static gint compose_save_to_outbox             (Compose        *compose,
-                                                const gchar    *file);
 static gint compose_remove_reedit_target       (Compose        *compose);
 static gint compose_queue                      (Compose        *compose,
                                                 gint           *msgnum,
                                                 FolderItem     **item);
+static gint compose_queue_sub                  (Compose        *compose,
+                                                gint           *msgnum,
+                                                FolderItem     **item,
+                                                gboolean       check_subject);
 static void compose_write_attach               (Compose        *compose,
                                                 FILE           *fp);
 static gint compose_write_headers              (Compose        *compose,
@@ -262,6 +278,7 @@ static gint calc_cursor_xpos        (GtkSText       *text,
 
 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);
 
 /* callback functions */
 
@@ -349,6 +366,7 @@ 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_gtk_stext_action_cb        (Compose                   *compose,
@@ -401,6 +419,9 @@ static void compose_toggle_encrypt_cb       (gpointer        data,
 #endif
 static void compose_toggle_return_receipt_cb(gpointer data, guint action,
                                             GtkWidget *widget);
+static void compose_set_priority_cb    (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
 
 static void compose_attach_drag_received_cb (GtkWidget         *widget,
                                             GdkDragContext     *drag_context,
@@ -424,8 +445,6 @@ static void to_activated            (GtkWidget      *widget,
                                         Compose        *compose);
 static void newsgroups_activated       (GtkWidget      *widget,
                                         Compose        *compose);
-static void subject_activated          (GtkWidget      *widget,
-                                        Compose        *compose);
 static void cc_activated               (GtkWidget      *widget,
                                         Compose        *compose);
 static void bcc_activated              (GtkWidget      *widget,
@@ -434,11 +453,17 @@ 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 void compose_attach_parts       (Compose        *compose,
-                                        MsgInfo        *msginfo);
-
+static void text_activated             (GtkWidget      *widget,
+                                        Compose        *compose);
+static void text_inserted              (GtkWidget      *widget,
+                                        const gchar    *text,
+                                        gint            length,
+                                        gint           *position,
+                                        Compose        *compose);
 static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
                                  gboolean to_all,
                                  gboolean ignore_replyto,
@@ -460,9 +485,7 @@ static void compose_check_backwards    (Compose *compose);
 static void compose_check_forwards_go     (Compose *compose);
 #endif
 
-static gboolean compose_send_control_enter (Compose *compose);
-static void text_activated                (GtkWidget   *widget,
-                                           Compose     *compose);
+static gboolean compose_send_control_enter     (Compose        *compose);
 
 static GtkItemFactoryEntry compose_popup_entries[] =
 {
@@ -488,6 +511,8 @@ static GtkItemFactoryEntry compose_entries[] =
        {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"),
@@ -572,8 +597,6 @@ static GtkItemFactoryEntry compose_entries[] =
                                        "<control><alt>L", compose_wrap_line_all, 0, NULL},
        {N_("/_Edit/Edit with e_xternal editor"),
                                        "<shift><control>X", compose_ext_editor_cb, 0, NULL},
-       {N_("/_Edit/---"),              NULL, NULL, 0, "<Separator>"},
-       {N_("/_Edit/Actio_ns"),         NULL, NULL, 0, "<Branch>"},
 #if USE_PSPELL
        {N_("/_Spelling"),              NULL, NULL, 0, "<Branch>"},
        {N_("/_Spelling/_Check all or check selection"),
@@ -627,12 +650,20 @@ static GtkItemFactoryEntry compose_entries[] =
        {N_("/_Message/Si_gn"),         NULL, compose_toggle_sign_cb   , 0, "<ToggleItem>"},
        {N_("/_Message/_Encrypt"),      NULL, compose_toggle_encrypt_cb, 0, "<ToggleItem>"},
 #endif /* USE_GPGME */
+       {N_("/_Message/---"),           NULL,           NULL,   0, "<Separator>"},
+       {N_("/_Message/_Priority"),     NULL,           NULL,   0, "<Branch>"},
+       {N_("/_Message/Priority/_Highest"), NULL, compose_set_priority_cb, PRIORITY_HIGHEST, "<RadioItem>"},
+       {N_("/_Message/Priority/Hi_gh"),    NULL, compose_set_priority_cb, PRIORITY_HIGH, "/Message/Priority/Highest"},
+       {N_("/_Message/Priority/_Normal"),  NULL, compose_set_priority_cb, PRIORITY_NORMAL, "/Message/Priority/Highest"},
+       {N_("/_Message/Priority/Lo_w"),    NULL, compose_set_priority_cb, PRIORITY_LOW, "/Message/Priority/Highest"},
+       {N_("/_Message/Priority/_Lowest"),  NULL, compose_set_priority_cb, PRIORITY_LOWEST, "/Message/Priority/Highest"},
        {N_("/_Message/---"),           NULL,           NULL,   0, "<Separator>"},
        {N_("/_Message/_Request Return Receipt"),       NULL, compose_toggle_return_receipt_cb, 0, "<ToggleItem>"},
-       {N_("/_Tool"),                  NULL, NULL, 0, "<Branch>"},
-       {N_("/_Tool/Show _ruler"),      NULL, compose_toggle_ruler_cb, 0, "<ToggleItem>"},
-       {N_("/_Tool/_Address book"),    "<shift><control>A", compose_address_cb , 0, NULL},
-       {N_("/_Tool/_Template"),        NULL, NULL, 0, "<Branch>"},
+       {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}
 };
@@ -642,24 +673,19 @@ static GtkTargetEntry compose_mime_types[] =
        {"text/uri-list", 0, 0}
 };
 
-Compose *compose_new(PrefsAccount *account)
-{
-       return compose_generic_new(account, NULL, NULL);
-}
-
-Compose *compose_bounce(PrefsAccount *account, MsgInfo *msginfo)
+Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo)
 {
        Compose *c;
        gchar *filename;
        GtkItemFactory *ifactory;
        
-       c = compose_generic_new(account, NULL, NULL);
+       c = compose_generic_new(account, NULL, NULL, NULL);
 
        filename = procmsg_get_message_file(msginfo);
        if (filename == NULL)
                return NULL;
 
-       c->bounce_filename = filename;
+       c->redirect_filename = filename;
 
        if (msginfo->subject)
                gtk_entry_set_text(GTK_ENTRY(c->subject_entry),
@@ -688,7 +714,7 @@ Compose *compose_bounce(PrefsAccount *account, MsgInfo *msginfo)
        menu_set_sensitive(ifactory, "/Message/Encrypt", FALSE);
 #endif
        menu_set_sensitive(ifactory, "/Message/Request Return Receipt", FALSE);
-       menu_set_sensitive(ifactory, "/Tool/Template", FALSE);
+       menu_set_sensitive(ifactory, "/Tools/Template", FALSE);
        
        gtk_widget_set_sensitive(c->insert_btn, FALSE);
        gtk_widget_set_sensitive(c->attach_btn, FALSE);
@@ -699,19 +725,24 @@ Compose *compose_bounce(PrefsAccount *account, MsgInfo *msginfo)
        return c;
 }
 
-Compose *compose_new_with_recipient(PrefsAccount *account, const gchar *mailto)
+Compose *compose_new(PrefsAccount *account, const gchar *mailto,
+                    GPtrArray *attach_files)
 {
-       return compose_generic_new(account, mailto, NULL);
+       return compose_generic_new(account, mailto, NULL, attach_files);
 }
 
 Compose *compose_new_with_folderitem(PrefsAccount *account, FolderItem *item)
 {
-       return compose_generic_new(account, NULL, item);
+       return compose_generic_new(account, NULL, item, NULL);
 }
 
-Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderItem *item)
+Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderItem *item,
+                            GPtrArray *attach_files)
 {
        Compose *compose;
+       GtkSText *text;
+       GtkItemFactory *ifactory;
+       gboolean grab_focus_on_last = TRUE;
 
        if (item && item->prefs && item->prefs->enable_default_account)
                account = account_find_from_id(item->prefs->default_account);
@@ -720,31 +751,57 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI
        g_return_val_if_fail(account != NULL, NULL);
 
        compose = compose_create(account, COMPOSE_NEW);
+       ifactory = gtk_item_factory_from_widget(compose->menubar);
+
        compose->replyinfo = NULL;
 
+       text = GTK_STEXT(compose->text);
+       gtk_stext_freeze(text);
+
        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);
+       gtk_editable_set_position(GTK_EDITABLE(text), 0);
+       gtk_stext_set_point(text, 0);
+
+       gtk_stext_thaw(text);
+
+       /* workaround for initial XIM problem */
+       gtk_widget_grab_focus(compose->text);
+       gtkut_widget_wait_for_draw(compose->text);
 
        if (account->protocol != A_NNTP) {
-               if (mailto) {
+               if (mailto && *mailto != '\0') {
                        compose_entries_set(compose, mailto);
 
                } else if(item && item->prefs->enable_default_to) {
                        compose_entry_append(compose, item->prefs->default_to, COMPOSE_TO);
+                       compose_entry_select(compose, item->prefs->default_to);
+                       grab_focus_on_last = FALSE;
                }
                if (item && item->ret_rcpt) {
-                       GtkItemFactory *ifactory;
-               
-                       ifactory = gtk_item_factory_from_widget(compose->menubar);
                        menu_set_toggle(ifactory, "/Message/Request Return Receipt", TRUE);
                }
        } else {
                if (mailto) {
                        compose_entry_append(compose, mailto, 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, "/Message/Request Return Receipt", FALSE); 
        }
+
+       if (attach_files) {
+               gint i;
+               gchar *file;
+
+               for (i = 0; i < attach_files->len; i++) {
+                       file = g_ptr_array_index(attach_files, i);
+                       compose_attach_append(compose, file, file, NULL);
+               }
+       }
+
        compose_show_first_last_header(compose, TRUE);
 
        /* Set save folder */
@@ -756,8 +813,10 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI
                gtk_entry_set_text(GTK_ENTRY(compose->savemsg_entry), folderidentifier);
                g_free(folderidentifier);
        }
-
-       gtk_widget_grab_focus(compose->header_last->entry);
+       
+       /* Grab focus on last header only if no default_to was set */
+       if(grab_focus_on_last)
+               gtk_widget_grab_focus(compose->header_last->entry);
 
        if (prefs_common.auto_exteditor)
                compose_exec_ext_editor(compose);
@@ -872,14 +931,8 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
        } else
                reply_account = account;
 
-       MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_FORWARDED);
-       MSG_SET_PERM_FLAGS(msginfo->flags, MSG_REPLIED);
-       if (MSG_IS_IMAP(msginfo->flags))
-               imap_msg_set_perm_flags(msginfo, MSG_REPLIED);
-       CHANGE_FLAGS(msginfo);
-
        compose = compose_create(account, COMPOSE_REPLY);
-       compose->replyinfo = procmsg_msginfo_copy(msginfo);
+       compose->replyinfo = procmsg_msginfo_new_ref(msginfo);
 
 #if 0 /* NEW COMPOSE GUI */
        if (followup_and_reply_to) {
@@ -946,219 +999,6 @@ static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
 
 static void set_toolbar_style(Compose *compose);
 
-static gchar *procmime_get_file_name(MimeInfo *mimeinfo)
-{
-       gchar *base;
-       gchar *filename;
-
-       g_return_val_if_fail(mimeinfo != NULL, NULL);
-
-       base = mimeinfo->filename ? mimeinfo->filename
-               : mimeinfo->name ? mimeinfo->name : NULL;
-
-       if (MIME_TEXT_HTML == mimeinfo->mime_type && base == NULL){
-               filename = g_strdup_printf("%s%smimetmp.%08x.html",
-                                          get_mime_tmp_dir(),
-                                          G_DIR_SEPARATOR_S,
-                                          (gint)mimeinfo);
-               return filename;
-       }
-       else {
-               base = base ? base : "";
-               base = g_basename(base);
-               if (*base == '\0') {
-                       filename = g_strdup_printf("%s%smimetmp.%08x",
-                                                  get_mime_tmp_dir(),
-                                                  G_DIR_SEPARATOR_S,
-                                                  (gint)mimeinfo);
-                       return filename;
-               }
-       }
-
-       filename = g_strconcat(get_mime_tmp_dir(), G_DIR_SEPARATOR_S,
-                              base, NULL);
-
-       return filename;
-}
-
-static gchar *mime_extract_file(gchar *source, MimeInfo *partinfo)
-{
-       gchar *filename;
-
-       if (!partinfo) return NULL;
-
-       filename = procmime_get_file_name(partinfo);
-
-       if (procmime_get_part(filename, source, partinfo) < 0)
-               alertpanel_error
-                       (_("Can't get the part of multipart message."));
-
-       return filename;
-}
-
-static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
-{
-       FILE *fp;
-       gchar *file;
-       MimeInfo *mimeinfo;
-       MsgInfo *tmpmsginfo;
-       gchar *p;
-       gchar *boundary;
-       gint boundary_len = 0;
-       gchar buf[BUFFSIZE];
-       glong fpos, prev_fpos;
-       gint npart;
-       gchar *source;
-       gchar *filename;
-
-       g_return_if_fail(msginfo != NULL);
-       
-#if USE_GPGME
-       for (;;) {
-               if ((fp = procmsg_open_message(msginfo)) == NULL) return;
-               mimeinfo = procmime_scan_mime_header(fp, MIME_TEXT);
-               if (!mimeinfo) break;
-
-               if (!MSG_IS_ENCRYPTED(msginfo->flags) &&
-                   rfc2015_is_encrypted(mimeinfo)) {
-                       MSG_SET_TMP_FLAGS(msginfo->flags, MSG_ENCRYPTED);
-               }
-               if (MSG_IS_ENCRYPTED(msginfo->flags) &&
-                   !msginfo->plaintext_file  &&
-                   !msginfo->decryption_failed) {
-                       rfc2015_decrypt_message(msginfo, mimeinfo, fp);
-                       if (msginfo->plaintext_file &&
-                           !msginfo->decryption_failed) {
-                               fclose(fp);
-                               continue;
-                       }
-               }
-               
-               break;
-       }
-#else /* !USE_GPGME */
-       if ((fp = procmsg_open_message(msginfo)) == NULL) return;
-       mimeinfo = procmime_scan_mime_header(fp, MIME_TEXT);
-#endif /* USE_GPGME */
-
-       fclose(fp);
-       if (!mimeinfo) return;
-       if (mimeinfo->mime_type == MIME_TEXT)
-               return;
-
-       if ((fp = procmsg_open_message(msginfo)) == NULL) return;
-
-       g_return_if_fail(mimeinfo != NULL);
-       g_return_if_fail(mimeinfo->mime_type != MIME_TEXT);
-
-       if (mimeinfo->mime_type == MIME_MULTIPART) {
-               g_return_if_fail(mimeinfo->boundary != NULL);
-               g_return_if_fail(mimeinfo->sub == NULL);
-       }
-       g_return_if_fail(fp != NULL);
-
-       boundary = mimeinfo->boundary;
-
-       if (boundary) {
-               boundary_len = strlen(boundary);
-
-               /* look for first boundary */
-               while ((p = fgets(buf, sizeof(buf), fp)) != NULL)
-                       if (IS_BOUNDARY(buf, boundary, boundary_len)) break;
-               if (!p) {
-                       fclose(fp);
-                       return;
-               }
-       }
-
-       if ((fpos = ftell(fp)) < 0) {
-               perror("ftell");
-               fclose(fp);
-               return;
-       }
-
-       for (npart = 0;; npart++) {
-               MimeInfo *partinfo;
-               gboolean eom = FALSE;
-
-               prev_fpos = fpos;
-
-               partinfo = procmime_scan_mime_header(fp, MIME_TEXT);
-               if (!partinfo) break;
-
-               if (npart != 0)
-                       procmime_mimeinfo_insert(mimeinfo, partinfo);
-               else
-                       procmime_mimeinfo_free(partinfo);
-
-               /* look for next boundary */
-               buf[0] = '\0';
-               while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
-                       if (IS_BOUNDARY(buf, boundary, boundary_len)) {
-                               if (buf[2 + boundary_len]     == '-' &&
-                                   buf[2 + boundary_len + 1] == '-')
-                                       eom = TRUE;
-                               break;
-                       }
-               }
-               if (p == NULL)
-                       eom = TRUE;     /* broken MIME message */
-               fpos = ftell(fp);
-
-               partinfo->size = fpos - prev_fpos - strlen(buf);
-
-               if (eom) break;
-       }
-
-       source = procmsg_get_message_file_path(msginfo);
-
-       g_return_if_fail(mimeinfo != NULL);
-
-       if (!mimeinfo->main && mimeinfo->parent)
-               {
-                       filename = mime_extract_file(source, mimeinfo);
-
-                       compose_attach_append_with_type(compose, filename,
-                                                       mimeinfo->content_type,
-                                                       mimeinfo->mime_type);
-
-                       g_free(filename);
-               }
-
-       if (mimeinfo->sub && mimeinfo->sub->children)
-               {
-                       filename = mime_extract_file(source, mimeinfo->sub);
-
-                       compose_attach_append_with_type(compose, filename,
-                                                       mimeinfo->content_type,
-                                                       mimeinfo->sub->mime_type);
-
-                       g_free(filename);
-               }
-
-       if (mimeinfo->children) {
-               MimeInfo *child;
-
-               child = mimeinfo->children;
-               while (child) {
-                       filename = mime_extract_file(source, child);
-
-                       compose_attach_append_with_type(compose, filename,
-                                                       child->content_type,
-                                                       child->mime_type);
-
-                       g_free(filename);
-
-                       child = child->next;
-               }
-       }
-
-       fclose(fp);
-
-       procmime_mimeinfo_free_all(mimeinfo);
-}
-
-
 #define INSERT_FW_HEADER(var, hdr) \
 if (msginfo->var && *msginfo->var) { \
        gtk_stext_insert(text, NULL, NULL, NULL, hdr, -1); \
@@ -1218,31 +1058,33 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
        text = GTK_STEXT(compose->text);
        gtk_stext_freeze(text);
 
-       if (as_attach) {
-               gchar *msgfile;
 
-               msgfile = procmsg_get_message_file_path(msginfo);
-               if (!is_file_exist(msgfile))
-                       g_warning(_("%s: file not exist\n"), msgfile);
-               else
-                       compose_attach_append(compose, msgfile,
-                                             MIME_MESSAGE_RFC822);
+               if (as_attach) {
+                       gchar *msgfile;
 
-               g_free(msgfile);
-       } else {
-               gchar *qmark;
-               gchar *quote_str;
+                       msgfile = procmsg_get_message_file_path(msginfo);
+                       if (!is_file_exist(msgfile))
+                               g_warning(_("%s: file not exist\n"), msgfile);
+                       else
+                               compose_attach_append(compose, msgfile, msgfile,
+                                                     "message/rfc822");
 
-               if (prefs_common.fw_quotemark && *prefs_common.fw_quotemark)
-                       qmark = prefs_common.fw_quotemark;
-               else
-                       qmark = "> ";
+                       g_free(msgfile);
+               } else {
+                       gchar *qmark;
+                       gchar *quote_str;
 
-               quote_str = compose_quote_fmt(compose, msginfo,
-                                             prefs_common.fw_quotefmt, qmark,
-                                             body);
-               compose_attach_parts(compose, msginfo);
-       }
+                       if (prefs_common.fw_quotemark &&
+                           *prefs_common.fw_quotemark)
+                               qmark = prefs_common.fw_quotemark;
+                       else
+                               qmark = "> ";
+
+                       quote_str = compose_quote_fmt(compose, msginfo,
+                                                     prefs_common.fw_quotefmt,
+                                                     qmark, body);
+                       compose_attach_parts(compose, msginfo);
+               }
 
        if (prefs_common.auto_sig)
                compose_insert_sig(compose);
@@ -1309,8 +1151,8 @@ Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_list)
                if (!is_file_exist(msgfile))
                        g_warning(_("%s: file not exist\n"), msgfile);
                else
-                       compose_attach_append(compose, msgfile,
-                               MIME_MESSAGE_RFC822);
+                       compose_attach_append(compose, msgfile, msgfile,
+                               "message/rfc822");
                g_free(msgfile);
        }
 
@@ -1423,8 +1265,6 @@ GList *compose_get_compose_list(void)
 void compose_entry_append(Compose *compose, const gchar *address,
                          ComposeEntryType type)
 {
-       GtkEntry *entry;
-       const gchar *text;
        gchar *header;
 
        if (!address || *address == '\0') return;
@@ -1478,6 +1318,20 @@ void compose_entry_append(Compose *compose, const gchar *address,
        compose_add_header_entry(compose, header, (gchar *)address);
 }
 
+void compose_entry_select (Compose *compose, const gchar *mailto)
+{
+       GSList *header_list;
+               
+       for (header_list = compose->header_list; header_list != NULL; header_list = header_list->next) {
+               GtkEntry * entry = GTK_ENTRY(((ComposeHeaderEntry *)header_list->data)->entry);
+
+               if (gtk_entry_get_text(entry) && !g_strcasecmp(gtk_entry_get_text(entry), mailto)) {
+                       gtk_entry_select_region(entry, 0, -1);
+                       gtk_widget_grab_focus(GTK_WIDGET(entry));
+               }
+       }
+}
+
 static void compose_entries_set(Compose *compose, const gchar *mailto)
 {
        gchar *subject = NULL;
@@ -1557,6 +1411,7 @@ static gint compose_parse_header(Compose *compose, MsgInfo *msginfo)
                                       {"Followup-To:",    NULL, FALSE},
                                       {"X-Mailing-List:", NULL, FALSE},
                                       {"X-BeenThere:",    NULL, FALSE},
+                                      {"X-Priority:",     NULL, FALSE},
                                       {NULL,              NULL, FALSE}};
 
        enum
@@ -1568,7 +1423,8 @@ static gint compose_parse_header(Compose *compose, MsgInfo *msginfo)
                H_NEWSGROUPS     = 4,
                H_FOLLOWUP_TO    = 5,
                H_X_MAILING_LIST = 6,
-               H_X_BEENTHERE    = 7
+               H_X_BEENTHERE    = 7,
+               H_X_PRIORITY     = 8
        };
 
        FILE *fp;
@@ -1637,6 +1493,22 @@ static gint compose_parse_header(Compose *compose, MsgInfo *msginfo)
                hentry[H_FOLLOWUP_TO].body = NULL;
        }
 
+       if (compose->mode == COMPOSE_REEDIT)
+               if (hentry[H_X_PRIORITY].body != NULL) {
+                       gint priority;
+                       
+                       priority = atoi(hentry[H_X_PRIORITY].body);
+                       g_free(hentry[H_X_PRIORITY].body);
+                       
+                       hentry[H_X_PRIORITY].body = NULL;
+                       
+                       if (priority < PRIORITY_HIGHEST || 
+                           priority > PRIORITY_LOWEST)
+                               priority = PRIORITY_NORMAL;
+                       
+                       compose->priority =  priority;
+               }
        if (compose->mode == COMPOSE_REEDIT && msginfo->inreplyto)
                compose->inreplyto = g_strdup(msginfo->inreplyto);
        else if (compose->mode != COMPOSE_REEDIT &&
@@ -1714,11 +1586,15 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
                                const gchar *body)
 {
        GtkSText *text = GTK_STEXT(compose->text);
+       static MsgInfo dummyinfo;
        gchar *quote_str = NULL;
        gchar *buf;
        gchar *p, *lastp;
        gint len;
 
+       if (!msginfo)
+               msginfo = &dummyinfo;
+
        if (qmark != NULL) {
                quote_fmt_init(msginfo, NULL, NULL);
                quote_fmt_scan_string(qmark);
@@ -1888,6 +1764,8 @@ static void compose_reedit_set_entry(Compose *compose, MsgInfo *msginfo)
        SET_ADDRESS(COMPOSE_BCC, compose->bcc);
        SET_ADDRESS(COMPOSE_REPLYTO, compose->replyto);
 
+       compose_update_priority_menu_item(compose);
+
        compose_show_first_last_header(compose, TRUE);
 
 #if 0 /* NEW COMPOSE GUI */
@@ -1918,9 +1796,6 @@ static void compose_reedit_set_entry(Compose *compose, MsgInfo *msginfo)
 
 static void compose_exec_sig(Compose *compose, gchar *sigfile)
 {
-       FILE *tmpfp;
-       pid_t thepid;
-       gchar *sigtext;
        FILE  *sigprg;
        gchar  *buf;
        size_t buf_len = 128;
@@ -1998,7 +1873,7 @@ static void compose_insert_file(Compose *compose, const gchar *file)
 
        g_return_if_fail(file != NULL);
 
-       if ((fp = fopen(file, "r")) == NULL) {
+       if ((fp = fopen(file, "rb")) == NULL) {
                FILE_OP_ERROR(file, "fopen");
                return;
        }
@@ -2022,30 +1897,15 @@ static void compose_insert_file(Compose *compose, const gchar *file)
        fclose(fp);
 }
 
-static void compose_attach_info(Compose * compose, AttachInfo * ainfo,
-                               ContentType cnttype)
-{
-       gchar *text[N_ATTACH_COLS];
-       gint row;
-
-       text[COL_MIMETYPE] = ainfo->content_type;
-       text[COL_SIZE] = to_human_readable(ainfo->size);
-       text[COL_NAME] = ainfo->name;
-
-       row = gtk_clist_append(GTK_CLIST(compose->attach_clist), text);
-       gtk_clist_set_row_data(GTK_CLIST(compose->attach_clist), row, ainfo);
-
-       if (cnttype != MIME_MESSAGE_RFC822)
-               compose_changed_cb(NULL, compose);
-}
-
-static void compose_attach_append_with_type(Compose *compose,
-                                           const gchar *file,
-                                           const gchar *type,
-                                           ContentType cnttype)
+static void compose_attach_append(Compose *compose, const gchar *file,
+                                 const gchar *filename,
+                                 const gchar *content_type)
 {
        AttachInfo *ainfo;
+       gchar *text[N_ATTACH_COLS];
+       FILE *fp;
        off_t size;
+       gint row;
 
        if (!is_file_exist(file)) {
                g_warning(_("File %s doesn't exist\n"), file);
@@ -2056,9 +1916,15 @@ static void compose_attach_append_with_type(Compose *compose,
                return;
        }
        if (size == 0) {
-               alertpanel_notice(_("File %s is empty\n"), file);
+               alertpanel_notice(_("File %s is empty."), file);
+               return;
+       }
+       if ((fp = fopen(file, "rb")) == NULL) {
+               alertpanel_error(_("Can't read %s."), file);
                return;
        }
+       fclose(fp);
+
 #if 0 /* NEW COMPOSE GUI */
        if (!compose->use_attach) {
                GtkItemFactory *ifactory;
@@ -2066,7 +1932,7 @@ static void compose_attach_append_with_type(Compose *compose,
 
                ifactory = gtk_item_factory_from_widget(compose->menubar);
                menuitem = gtk_item_factory_get_item(ifactory,
-                                                    "/Message/Attach");
+                                                    "/View/Attachment");
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),
                                               TRUE);
        }
@@ -2074,74 +1940,99 @@ static void compose_attach_append_with_type(Compose *compose,
        ainfo = g_new0(AttachInfo, 1);
        ainfo->file = g_strdup(file);
 
-       if (cnttype == MIME_MESSAGE_RFC822) {
-               ainfo->encoding = ENC_7BIT;
-               ainfo->name = g_strdup_printf(_("Message: %s"),
-                                             g_basename(file));
+       if (content_type) {
+               ainfo->content_type = g_strdup(content_type);
+               if (!strcasecmp(content_type, "message/rfc822")) {
+                       ainfo->encoding = ENC_7BIT;
+                       ainfo->name = g_strdup_printf
+                               (_("Message: %s"),
+                                g_basename(filename ? filename : file));
+               } else {
+                       if (!g_strncasecmp(content_type, "text", 4))
+                               ainfo->encoding =
+                                       procmime_get_encoding_for_file(file);
+                       else
+                               ainfo->encoding = ENC_BASE64;
+                       ainfo->name = g_strdup
+                               (g_basename(filename ? filename : file));
+               }
        } else {
-               ainfo->encoding = ENC_BASE64;
-               ainfo->name = g_strdup(g_basename(file));
+               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))
+                       ainfo->encoding = procmime_get_encoding_for_file(file);
+               else
+                       ainfo->encoding = ENC_BASE64;
+               ainfo->name = g_strdup(g_basename(filename ? filename : file)); 
        }
-
-       ainfo->content_type = g_strdup(type);
        ainfo->size = size;
 
-       compose_attach_info(compose, ainfo, cnttype);
+       text[COL_MIMETYPE] = ainfo->content_type;
+       text[COL_SIZE] = to_human_readable(size);
+       text[COL_NAME] = ainfo->name;
+
+       row = gtk_clist_append(GTK_CLIST(compose->attach_clist), text);
+       gtk_clist_set_row_data(GTK_CLIST(compose->attach_clist), row, ainfo);
 }
 
-static void compose_attach_append(Compose *compose, const gchar *file,
-                                 ContentType cnttype)
+#define IS_FIRST_PART_TEXT(info) \
+       ((info->mime_type == MIME_TEXT || info->mime_type == MIME_TEXT_HTML || \
+         info->mime_type == MIME_TEXT_ENRICHED) || \
+        (info->mime_type == MIME_MULTIPART && info->content_type && \
+         !strcasecmp(info->content_type, "multipart/alternative") && \
+         (info->children && \
+          (info->children->mime_type == MIME_TEXT || \
+           info->children->mime_type == MIME_TEXT_HTML || \
+           info->children->mime_type == MIME_TEXT_ENRICHED))))
+
+static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
 {
-       AttachInfo *ainfo;
-       gchar *text[N_ATTACH_COLS];
-       off_t size;
-       gint row;
+       MimeInfo *mimeinfo;
+       MimeInfo *child;
+       gchar *infile;
+       gchar *outfile;
 
-       if (!is_file_exist(file)) {
-               g_warning(_("File %s doesn't exist\n"), file);
-               return;
-       }
-       if ((size = get_file_size(file)) < 0) {
-               g_warning(_("Can't get file size of %s\n"), file);
-               return;
-       }
-       if (size == 0) {
-               alertpanel_notice(_("File %s is empty\n"), file);
+       mimeinfo = procmime_scan_message(msginfo);
+       if (!mimeinfo) return;
+
+       /* skip first text (presumably message body) */
+       child = mimeinfo->children;
+       if (!child || IS_FIRST_PART_TEXT(mimeinfo)) {
+               procmime_mimeinfo_free_all(mimeinfo);
                return;
        }
-#if 0 /* NEW COMPOSE GUI */
-       if (!compose->use_attach) {
-               GtkItemFactory *ifactory;
-               GtkWidget *menuitem;
+       if (IS_FIRST_PART_TEXT(child))
+               child = child->next;
 
-               ifactory = gtk_item_factory_from_widget(compose->menubar);
-               menuitem = gtk_item_factory_get_item(ifactory,
-                                                    "/View/Attachment");
-               gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),
-                                              TRUE);
-       }
-#endif
-       ainfo = g_new0(AttachInfo, 1);
-       ainfo->file = g_strdup(file);
+       infile = procmsg_get_message_file_path(msginfo);
 
-       if (cnttype == MIME_MESSAGE_RFC822) {
-               ainfo->content_type = g_strdup("message/rfc822");
-               ainfo->encoding = ENC_7BIT;
-               ainfo->name = g_strdup_printf(_("Message: %s"),
-                                             g_basename(file));
-       } else {
-               ainfo->content_type = procmime_get_mime_type(file);
-               if (!ainfo->content_type)
-                       ainfo->content_type =
-                               g_strdup("application/octet-stream");
-               ainfo->encoding = ENC_BASE64;
-               ainfo->name = g_strdup(g_basename(file));
+       while (child != NULL) {
+               if (child->children || child->mime_type == MIME_MULTIPART) {
+                       child = procmime_mimeinfo_next(child);
+                       continue;
+               }
+
+               outfile = procmime_get_tmp_file_name(child);
+               if (procmime_get_part(outfile, infile, child) < 0)
+                       g_warning(_("Can't get the part of multipart message."));
+               else
+                       compose_attach_append
+                               (compose, outfile,
+                                child->filename ? child->filename : child->name,
+                                child->content_type);
+
+               child = child->next;
        }
-       ainfo->size = size;
 
-       compose_attach_info(compose, ainfo, cnttype);
+       g_free(infile);
+       procmime_mimeinfo_free_all(mimeinfo);
 }
 
+#undef IS_FIRST_PART_TEXT
+
 #define GET_CHAR(pos, buf, len)                                                     \
 {                                                                           \
        if (text->use_wchar)                                                 \
@@ -2152,6 +2043,9 @@ static void compose_attach_append(Compose *compose, const gchar *file,
        }                                                                    \
 }
 
+#define INDENT_CHARS   ">|#"
+#define SPACE_CHARS    " \t"
+
 static void compose_wrap_line(Compose *compose)
 {
        GtkSText *text = GTK_STEXT(compose->text);
@@ -2192,7 +2086,8 @@ static void compose_wrap_line(Compose *compose)
                        }
                        line_end = 1;
                } else {
-                       if (ch_len == 1 && strchr(">:#", *cbuf))
+                       if (ch_len == 1 
+                           && strchr(prefs_common.quote_chars, *cbuf))
                                quoted = 1;
                        else if (ch_len != 1 || !isspace(*cbuf))
                                quoted = 0;
@@ -2214,7 +2109,8 @@ static void compose_wrap_line(Compose *compose)
                        }
                        line_end = 1;
                } else {
-                       if (line_end && ch_len == 1 && strchr(">:#", *cbuf))
+                       if (line_end && ch_len == 1 &&
+                           strchr(prefs_common.quote_chars, *cbuf))
                                goto compose_end; /* quoted part */
 
                        line_end = 0;
@@ -2311,33 +2207,109 @@ compose_end:
        gtk_stext_thaw(text);
 }
 
+#undef WRAP_DEBUG
+#ifdef WRAP_DEBUG
+/* Darko: used when I debug wrapping */
+void dump_text(GtkSText *text, int pos, int tlen, int breakoncr)
+{
+       gint i;
+       gchar ch;
+
+       printf("%d [", pos);
+       for (i = pos; i < tlen; i++) {
+               ch = GTK_STEXT_INDEX(text, i);
+               if (breakoncr && ch == '\n')
+                       break;
+               printf("%c", ch);
+       }
+       printf("]\n");
+}
+#endif
+
+typedef enum {
+       WAIT_FOR_SPACE,
+       WAIT_FOR_INDENT_CHAR,
+       WAIT_FOR_INDENT_CHAR_OR_SPACE
+} IndentState;
+
+/* return indent length, we allow:
+   > followed by spaces/tabs
+   | followed by spaces/tabs
+   uppercase characters immediately followed by >,
+   and the repeating sequences of the above */
 /* return indent length */
 static guint get_indent_length(GtkSText *text, guint start_pos, guint text_len)
 {
-       gint indent_len = 0;
-       gint i, ch_len;
+       guint i_len = 0;
+       guint i, ch_len, alnum_cnt = 0;
+       IndentState state = WAIT_FOR_INDENT_CHAR;
        gchar cbuf[MB_LEN_MAX];
+       gboolean is_space;
+       gboolean is_indent;
 
        for (i = start_pos; i < text_len; i++) {
                GET_CHAR(i, cbuf, ch_len);
                if (ch_len > 1)
                        break;
-               /* allow space, tab, > or | */
-               if (cbuf[0] != ' ' && cbuf[0] != '\t' &&
-                   cbuf[0] != '>' && cbuf[0] != '|')
+
+               if (cbuf[0] == '\n')
+                       break;
+
+               is_indent = strchr(prefs_common.quote_chars, cbuf[0]) ? TRUE : FALSE;
+               is_space = strchr(SPACE_CHARS, cbuf[0]) ? TRUE : FALSE;
+
+               switch (state) {
+               case WAIT_FOR_SPACE:
+                       if (is_space == FALSE)
+                               goto out;
+                       state = WAIT_FOR_INDENT_CHAR_OR_SPACE;
+                       break;
+               case WAIT_FOR_INDENT_CHAR_OR_SPACE:
+                       if (is_indent == FALSE && is_space == FALSE &&
+                           !isupper(cbuf[0]))
+                               goto out;
+                       if (is_space == TRUE) {
+                               alnum_cnt = 0;
+                               state = WAIT_FOR_INDENT_CHAR_OR_SPACE;
+                       } else if (is_indent == TRUE) {
+                               alnum_cnt = 0;
+                               state = WAIT_FOR_SPACE;
+                       } else {
+                               alnum_cnt++;
+                               state = WAIT_FOR_INDENT_CHAR;
+                       }
                        break;
-               indent_len++;
+               case WAIT_FOR_INDENT_CHAR:
+                       if (is_indent == FALSE && !isupper(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++;
        }
 
-       return indent_len;
+out:
+       if ((i_len > 0) && (state == WAIT_FOR_INDENT_CHAR))
+               i_len -= alnum_cnt;
+
+       return i_len;
 }
 
 /* insert quotation string when line was wrapped */
-static guint ins_quote(GtkSText *text, guint quote_len, guint indent_len,
+static guint ins_quote(GtkSText *text, guint indent_len,
                       guint prev_line_pos, guint text_len,
                       gchar *quote_fmt)
 {
-       guint i, ins_len;
+       guint i, ins_len = 0;
        gchar ch;
 
        if (indent_len) {
@@ -2346,32 +2318,29 @@ static guint ins_quote(GtkSText *text, guint quote_len, guint indent_len,
                        gtk_stext_insert(text, NULL, NULL, NULL, &ch, 1);
                }
                ins_len = indent_len;
-       } else {
-               gtk_stext_insert(text, NULL, NULL, NULL, quote_fmt, quote_len);
-               ins_len = quote_len;
        }
 
        return ins_len;
 }
 
-#undef WRAP_DEBUG
-#ifdef WRAP_DEBUG
-/* Darko: used when I debug wrapping */
-void dump_text(GtkSText *text, int pos, int tlen, int breakoncr)
+/* check if we should join the next line */
+static gboolean join_next_line(GtkSText *text, guint start_pos, guint tlen,
+                              guint prev_ilen)
 {
-       gint i;
-       gchar ch;
+       guint indent_len, ch_len;
+       gboolean do_join = FALSE;
+       gchar cbuf[MB_LEN_MAX];
 
-       printf("%d [", pos);
-       for (i = pos; i < tlen; i++) {
-               ch = GTK_STEXT_INDEX(text, i);
-               if (breakoncr && ch == '\n')
-                       break;
-               printf("%c", ch);
+       indent_len = get_indent_length(text, start_pos, tlen);
+
+       if ((indent_len > 0) && (indent_len == prev_ilen)) {
+               GET_CHAR(start_pos + indent_len, cbuf, ch_len);
+               if (ch_len > 0 && (cbuf[0] != '\n'))
+                       do_join = TRUE;
        }
-       printf("]\n");
+
+       return do_join;
 }
-#endif
 
 static void compose_wrap_line_all(Compose *compose)
 {
@@ -2381,7 +2350,7 @@ static void compose_wrap_line_all(Compose *compose)
        gint line_len = 0, cur_len = 0;
        gint ch_len;
        gboolean is_new_line = TRUE, do_delete = FALSE;
-       guint qlen = 0, i_len = 0;
+       guint i_len = 0;
        gboolean linewrap_quote = TRUE;
        guint linewrap_len = prefs_common.linewrap_len;
        gchar *qfmt = prefs_common.quotemark;
@@ -2397,19 +2366,13 @@ static void compose_wrap_line_all(Compose *compose)
        for (; cur_pos < tlen; cur_pos++) {
                /* mark position of new line - needed for quotation wrap */
                if (is_new_line) {
-                       if (linewrap_quote) {
-                               qlen = gtkut_stext_str_compare
-                                       (text, cur_pos, tlen, qfmt);
-                               if (qlen)
-                                       i_len = get_indent_length
-                                               (text, cur_pos, tlen);
-                               else
-                                       i_len = 0;
-                       }
+                       if (linewrap_quote)
+                               i_len = get_indent_length(text, cur_pos, tlen);
+
                        is_new_line = FALSE;
                        p_pos = cur_pos;
 #ifdef WRAP_DEBUG
-                       printf("new line i_len=%d qlen=%d p_pos=", i_len, qlen);
+                       printf("new line i_len=%d p_pos=", i_len);
                        dump_text(text, p_pos, tlen, 1);
 #endif
                }
@@ -2437,31 +2400,20 @@ static void compose_wrap_line_all(Compose *compose)
                /* we have encountered line break */
                if (ch_len == 1 && *cbuf == '\n') {
                        gint clen;
-                       guint ilen;
-                       gchar cb[MB_CUR_MAX];
+                       gchar cb[MB_LEN_MAX];
+
+                       /* should we join the next line */
+                       if ((i_len != cur_len) && do_delete &&
+                           join_next_line(text, cur_pos + 1, tlen, i_len))
+                               do_delete = TRUE;
+                       else
+                               do_delete = FALSE;
 
 #ifdef WRAP_DEBUG
-                       printf("found CR at %d next line is ", cur_pos);
+                       printf("found CR at %d do_del is %d next line is ",
+                              cur_pos, do_delete);
                        dump_text(text, cur_pos + 1, tlen, 1);
 #endif
-                       /* if it's just quotation + newline skip it */
-                       if (i_len && (cur_pos + 1 < tlen)) {
-                               /* check if text at new line matches indent */
-                               ilen =  gtkut_stext_str_compare_n
-                                       (text, cur_pos + 1, p_pos, i_len, tlen);
-                               if (cur_pos + ilen < tlen) {
-                                       GET_CHAR(cur_pos + ilen + 1, cb, clen);
-                                       /* no need to join the lines */
-                                       if (clen == 1 && cb[0] == '\n')
-                                               do_delete = FALSE;
-                               }
-                       /* if it's just newline skip it */
-                       } else if (do_delete && (cur_pos + 1 < tlen)) {
-                               GET_CHAR(cur_pos + 1, cb, clen);
-                               /* no need to join the lines */
-                               if (clen == 1 && cb[0] == '\n')
-                                       do_delete = FALSE;
-                       }
 
                        /* skip delete if it is continuous URL */
                        if (do_delete && (line_pos - p_pos <= i_len) &&
@@ -2469,8 +2421,8 @@ static void compose_wrap_line_all(Compose *compose)
                                do_delete = FALSE;
 
 #ifdef WRAP_DEBUG
-                       printf("qlen=%d l_len=%d wrap_len=%d do_del=%d\n",
-                               qlen, line_len, linewrap_len, do_delete);
+                       printf("l_len=%d wrap_len=%d do_del=%d\n",
+                               line_len, linewrap_len, do_delete);
 #endif
                        /* should we delete to perform smart wrapping */
                        if (line_len < linewrap_len && do_delete) {
@@ -2482,6 +2434,7 @@ static void compose_wrap_line_all(Compose *compose)
                                /* if text starts with quote fmt or with
                                   indent string, delete them */
                                if (i_len) {
+                                       guint ilen;
                                        ilen =  gtkut_stext_str_compare_n
                                                (text, cur_pos, p_pos, i_len,
                                                 tlen);
@@ -2490,13 +2443,6 @@ static void compose_wrap_line_all(Compose *compose)
                                                        (text, ilen);
                                                tlen -= ilen;
                                        }
-                               } else if (qlen) {
-                                       if (gtkut_stext_str_compare
-                                           (text, cur_pos, tlen, qfmt)) {
-                                               gtk_stext_forward_delete
-                                                       (text, qlen);
-                                               tlen -= qlen;
-                                       }
                                }
 
                                GET_CHAR(cur_pos, cb, clen);
@@ -2514,7 +2460,6 @@ static void compose_wrap_line_all(Compose *compose)
                                cur_pos = p_pos - 1;
                                line_pos = cur_pos;
                                line_len = cur_len = 0;
-                               qlen = 0;
                                do_delete = FALSE;
                                is_new_line = TRUE;
 #ifdef WRAP_DEBUG
@@ -2527,7 +2472,6 @@ static void compose_wrap_line_all(Compose *compose)
                        /* mark new line beginning */
                        line_pos = cur_pos + 1;
                        line_len = cur_len = 0;
-                       qlen = 0;
                        do_delete = FALSE;
                        is_new_line = TRUE;
                        continue;
@@ -2601,7 +2545,10 @@ static void compose_wrap_line_all(Compose *compose)
                        is_new_line = TRUE;
                        line_len = 0;
                        cur_len = 0;
-                       do_delete = TRUE;
+                       if (i_len)
+                               do_delete = TRUE;
+                       else
+                               do_delete = FALSE;
 #ifdef WRAP_DEBUG
                        printf("after CR insert ");
                        dump_text(text, line_pos, tlen, 1);
@@ -2609,7 +2556,7 @@ static void compose_wrap_line_all(Compose *compose)
 #endif
 
                        /* should we insert quotation ? */
-                       if (linewrap_quote && qlen) {
+                       if (linewrap_quote && i_len) {
                                /* only if line is not already quoted  */
                                if (!gtkut_stext_str_compare
                                        (text, line_pos, tlen, qfmt)) {
@@ -2617,8 +2564,8 @@ static void compose_wrap_line_all(Compose *compose)
 
                                        if (line_pos - p_pos > i_len) {
                                                ins_len = ins_quote
-                                                       (text, qlen, i_len,
-                                                        p_pos, tlen, qfmt);
+                                                       (text, i_len, p_pos,
+                                                        tlen, qfmt);
 
                                                /* gtk_stext_compact_buffer(text); */
                                                tlen += ins_len;
@@ -2707,7 +2654,7 @@ gboolean compose_check_for_valid_recipient(Compose *compose) {
        for(list = compose->header_list; list; list = list->next) {
                gchar *header;
                gchar *entry;
-               header = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(((ComposeHeaderEntry *)list->data)->combo)->entry));
+               header = gtk_editable_get_chars(GTK_EDITABLE(GTK_COMBO(((ComposeHeaderEntry *)list->data)->combo)->entry), 0, -1);
                entry = gtk_editable_get_chars(GTK_EDITABLE(((ComposeHeaderEntry *)list->data)->entry), 0, -1);
                g_strstrip(entry);
                if(entry[0] != '\0') {
@@ -2724,17 +2671,44 @@ gboolean compose_check_for_valid_recipient(Compose *compose) {
                                }
                        }
                }
+               g_free(header);
                g_free(entry);
        }
        return recipient_found;
 }
 
+static gboolean compose_check_entries(Compose *compose, gboolean check_subject)
+{
+       gchar *str;
+
+       if (compose_check_for_valid_recipient(compose) == FALSE) {
+               alertpanel_error(_("Recipient is not specified."));
+               return FALSE;
+       }
+
+       str = gtk_entry_get_text(GTK_ENTRY(compose->subject_entry));
+       if (*str == '\0' && check_subject == TRUE) {
+               AlertValue aval;
+
+               aval = alertpanel(_("Send"),
+                                 _("Subject is empty. Send it anyway?"),
+                                 _("Yes"), _("No"), NULL);
+               if (aval != G_ALERTDEFAULT)
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
 gint compose_send(Compose *compose)
 {
        gint msgnum;
        FolderItem *folder;
        gint val;
 
+       if (compose_check_entries(compose, TRUE) == FALSE)
+               return -1;
+
        val = compose_queue(compose, &msgnum, &folder);
        if (val) {
                alertpanel_error(_("Could not queue message for sending"));
@@ -2742,10 +2716,9 @@ gint compose_send(Compose *compose)
        }
        
        val = procmsg_send_message_queue(folder_item_fetch_msg(folder, msgnum));
-       if(!val) {
-               folder_item_remove_msg(folder, msgnum);
-               folderview_update_item(folder, TRUE);
-       }
+
+       folder_item_remove_msg(folder, msgnum);
+       folderview_update_item(folder, TRUE);
 
        return val;
 }
@@ -2764,15 +2737,14 @@ gint compose_send(Compose *compose)
 
        lock = TRUE;
 
-       if(!compose_check_for_valid_recipient(compose)) {
-               alertpanel_error(_("Recipient is not specified."));
+       if (compose_check_entries(compose, TRUE) == FALSE) {
                lock = FALSE;
                return 1;
        }
 
        /* write to temporary file */
-       g_snprintf(tmp, sizeof(tmp), "%s%ctmpmsg%d",
-                  get_rc_dir(), G_DIR_SEPARATOR, (gint)compose);
+       g_snprintf(tmp, sizeof(tmp), "%s%ctmpmsg.%08x",
+                  get_tmp_dir(), G_DIR_SEPARATOR, (gint)compose);
 
        if (prefs_common.linewrap_at_send)
                compose_wrap_line_all(compose);
@@ -2856,13 +2828,18 @@ gint compose_send(Compose *compose)
                                folderview_update_item
                                        (compose->targetinfo->folder, TRUE);
                }
-       }
+               /* save message to outbox */
+               if (prefs_common.savemsg) {
+                       FolderItem *outbox;
 
-       /* save message to outbox */
-       if (ok == 0 && prefs_common.savemsg) {
-               if (compose_save_to_outbox(compose, tmp) < 0)
-                       alertpanel_error
-                               (_("Can't save the message to outbox."));
+                       outbox = account_get_special_folder
+                               (compose->account, F_OUTBOX);
+                       if (procmsg_save_to_outbox(outbox, tmp, FALSE) < 0)
+                               alertpanel_error
+                                       (_("Can't save the message to Sent."));
+                       else
+                               folderview_update_item(outbox, TRUE);
+               }
        }
 
        unlink(tmp);
@@ -2875,8 +2852,8 @@ static gboolean compose_use_attach(Compose *compose) {
     return(gtk_clist_get_row_data(GTK_CLIST(compose->attach_clist), 0) != NULL);
 }
 
-static gint compose_bounce_write_headers_from_headerlist(Compose *compose, 
-                                                        FILE *fp)
+static gint compose_redirect_write_headers_from_headerlist(Compose *compose, 
+                                                          FILE *fp)
 {
        gchar buf[BUFFSIZE];
        gchar *str;
@@ -2884,17 +2861,14 @@ static gint compose_bounce_write_headers_from_headerlist(Compose *compose,
        GSList *list;
        ComposeHeaderEntry *headerentry;
        gchar *headerentryname;
-       gchar *header_w_colon;
        gchar *cc_hdr;
        gchar *to_hdr;
 
-       debug_print(_("Writing bounce header\n"));
+       debug_print("Writing redirect header\n");
+
+       cc_hdr = prefs_common.trans_hdr ? _("Cc:") : "Cc:";
+       to_hdr = prefs_common.trans_hdr ? _("To:") : "To:";
 
-       header_w_colon = g_strconcat("To:", NULL);
-       to_hdr = (prefs_common.trans_hdr ? gettext(header_w_colon) : header_w_colon);
-       header_w_colon = g_strconcat("Cc:", NULL);
-       cc_hdr = (prefs_common.trans_hdr ? gettext(header_w_colon) : header_w_colon);
-       
        first_address = TRUE;
        for(list = compose->header_list; list; list = list->next) {
                headerentry = ((ComposeHeaderEntry *)list->data);
@@ -2926,7 +2900,7 @@ static gint compose_bounce_write_headers_from_headerlist(Compose *compose,
        return(0);
 }
 
-static gint compose_bounce_write_headers(Compose *compose, FILE *fp)
+static gint compose_redirect_write_headers(Compose *compose, FILE *fp)
 {
        gchar buf[BUFFSIZE];
        gchar *str;
@@ -2936,11 +2910,11 @@ static gint compose_bounce_write_headers(Compose *compose, FILE *fp)
        g_return_val_if_fail(compose->account != NULL, -1);
        g_return_val_if_fail(compose->account->address != NULL, -1);
 
-       /* Date */
+       /* Resent-Date */
        get_rfc822_date(buf, sizeof(buf));
        fprintf(fp, "Resent-Date: %s\n", buf);
 
-       /* From */
+       /* Resent-From */
        if (compose->account->name && *compose->account->name) {
                compose_convert_header
                        (buf, sizeof(buf), compose->account->name,
@@ -2950,8 +2924,26 @@ static gint compose_bounce_write_headers(Compose *compose, FILE *fp)
        } else
                fprintf(fp, "Resent-From: %s\n", compose->account->address);
 
-       /* To */
-       compose_bounce_write_headers_from_headerlist(compose, fp);
+       /* Subject */
+       str = gtk_entry_get_text(GTK_ENTRY(compose->subject_entry));
+       if (*str != '\0') {
+               Xstrdup_a(str, str, return -1);
+               g_strstrip(str);
+               if (*str != '\0') {
+                       compose_convert_header(buf, sizeof(buf), str,
+                                              strlen("Subject: "));
+                       fprintf(fp, "Subject: %s\n", buf);
+               }
+       }
+
+       /* Resent-Message-ID */
+       if (compose->account->gen_msgid) {
+               compose_generate_msgid(compose, buf, sizeof(buf));
+               fprintf(fp, "Resent-Message-Id: <%s>\n", buf);
+               compose->msgid = g_strdup(buf);
+       }
+
+       compose_redirect_write_headers_from_headerlist(compose, fp);
 
        /* separator between header and body */
        fputs("\n", fp);
@@ -2959,19 +2951,19 @@ static gint compose_bounce_write_headers(Compose *compose, FILE *fp)
        return 0;
 }
 
-static gint compose_bounce_write_to_file(Compose *compose, const gchar *file)
+static gint compose_redirect_write_to_file(Compose *compose, const gchar *file)
 {
        FILE *fp;
        FILE *fdest;
        size_t len;
        gchar buf[BUFFSIZE];
 
-       if ((fp = fopen(compose->bounce_filename, "r")) == NULL) {
+       if ((fp = fopen(compose->redirect_filename, "rb")) == NULL) {
                FILE_OP_ERROR(file, "fopen");
                return -1;
        }
 
-       if ((fdest = fopen(file, "w")) == NULL) {
+       if ((fdest = fopen(file, "wb")) == NULL) {
                FILE_OP_ERROR(file, "fopen");
                fclose(fp);
                return -1;
@@ -2985,91 +2977,134 @@ static gint compose_bounce_write_to_file(Compose *compose, const gchar *file)
 
        while (procheader_get_unfolded_line(buf, sizeof(buf), fp)) {
                /* should filter returnpath, delivered-to */
-               if ((g_strncasecmp(buf, "Return-Path:",
-                                  strlen("Return-Path:")) == 0)
-                   || (g_strncasecmp(buf, "Delivered-To:",
-                                     strlen("Delivered-To:")) == 0))
+               if (g_strncasecmp(buf, "Return-Path:",
+                                  strlen("Return-Path:")) == 0 ||
+                   g_strncasecmp(buf, "Delivered-To:",
+                                 strlen("Delivered-To:")) == 0 ||
+                   g_strncasecmp(buf, "Received:",
+                                 strlen("Received:")) == 0 ||
+                   g_strncasecmp(buf, "Subject:",
+                                 strlen("Subject:")) == 0 ||
+                   g_strncasecmp(buf, "X-UIDL:",
+                                 strlen("X-UIDL:")) == 0)
                        continue;
 
                if (fputs(buf, fdest) == -1)
                        goto error;
 
-               if (g_strncasecmp(buf, "From:", strlen("From:")) == 0) {
-                       fputs(" (by way of ", fdest);
-                       if (compose->account->name
-                           && *compose->account->name) {
-                               compose_convert_header
-                                       (buf, sizeof(buf),
-                                        compose->account->name,
-                                        strlen("From: "));
-                               fprintf(fdest, "%s <%s>",
-                                       buf, compose->account->address);
-                       } else
-                               fprintf(fdest, "%s",
-                                       compose->account->address);
-                       fputs(")", fdest);
+               if (!prefs_common.redirect_keep_from) {
+                       if (g_strncasecmp(buf, "From:",
+                                         strlen("From:")) == 0) {
+                               fputs(" (by way of ", fdest);
+                               if (compose->account->name
+                                   && *compose->account->name) {
+                                       compose_convert_header
+                                               (buf, sizeof(buf),
+                                                compose->account->name,
+                                                strlen("From: "));
+                                       fprintf(fdest, "%s <%s>",
+                                               buf,
+                                               compose->account->address);
+                               } else
+                                       fprintf(fdest, "%s",
+                                               compose->account->address);
+                               fputs(")", fdest);
+                       }
                }
 
                if (fputs("\n", fdest) == -1)
                        goto error;
        }
 
-       compose_bounce_write_headers(compose, fdest);
+       compose_redirect_write_headers(compose, fdest);
 
-       while ((len = fread(buf, sizeof(gchar), BUFFSIZE, fp)) > 0) {
-               if (fwrite(buf, sizeof(gchar), len, fdest) == -1)
+       while ((len = fread(buf, sizeof(gchar), sizeof(buf), fp)) > 0) {
+               if (fwrite(buf, sizeof(gchar), len, fdest) != len) {
+                       FILE_OP_ERROR(file, "fwrite");
                        goto error;
+               }
        }
 
-       fclose(fdest);
        fclose(fp);
+       if (fclose(fdest) == EOF) {
+               FILE_OP_ERROR(file, "fclose");
+               unlink(file);
+               return -1;
+       }
 
        return 0;
  error:
-       fclose(fdest);
        fclose(fp);
+       fclose(fdest);
+       unlink(file);
 
        return -1;
 }
 
 
-#ifdef USE_GPGME
-/*
- * interfaces to rfc2015 to keep out the prefs stuff there.
+#if USE_GPGME
+/* interfaces to rfc2015 to keep out the prefs stuff there.
  * returns 0 on success and -1 on error. */
-static int compose_create_signers_list (Compose *compose, GSList **pkey_list)
+static gint compose_create_signers_list(Compose *compose, GSList **pkey_list)
 {
-       const char *keyid = NULL;
+       const gchar *key_id = NULL;
        GSList *key_list;
 
        switch (compose->account->sign_key) {
        case SIGN_KEY_DEFAULT:
                *pkey_list = NULL;
-               return 0;               /* nothing to do */
-
+               return 0;
        case SIGN_KEY_BY_FROM:
-               keyid = compose->account->address;
+               key_id = compose->account->address;
                break;
-
        case SIGN_KEY_CUSTOM:
-               keyid = compose->account->sign_key_id;
+               key_id = compose->account->sign_key_id;
                break;
-
        default:
-               g_assert_not_reached ();
+               break;
        }
 
-       key_list = rfc2015_create_signers_list(keyid);
+       key_list = rfc2015_create_signers_list(key_id);
 
        if (!key_list) {
-           alertpanel_error("Could not find any key associated with currently "
-                               "selected keyid `%s'!", keyid);
-           return -1;
+               alertpanel_error(_("Could not find any key associated with "
+                                  "currently selected key id `%s'."), key_id);
+               return -1;
        }
-       
+
        *pkey_list = key_list;
        return 0;
 }
+
+/* clearsign message body text */
+static gint compose_clearsign_text(Compose *compose, gchar **text)
+{
+       GSList *key_list;
+       gchar *tmp_file;
+
+       tmp_file = get_tmp_file();
+       if (str_write_to_file(*text, tmp_file) < 0) {
+               g_free(tmp_file);
+               return -1;
+       }
+
+       if (canonicalize_file_replace(tmp_file) < 0 ||
+           compose_create_signers_list(compose, &key_list) < 0 ||
+           rfc2015_clearsign(tmp_file, key_list) < 0) {
+               unlink(tmp_file);
+               g_free(tmp_file);
+               return -1;
+       }
+
+       g_free(*text);
+       *text = file_read_to_str(tmp_file);
+       unlink(tmp_file);
+       g_free(tmp_file);
+       if (*text == NULL)
+               return -1;
+
+       return 0;
+}
 #endif /* USE_GPGME */
 
 static gint compose_write_to_file(Compose *compose, const gchar *file,
@@ -3082,7 +3117,7 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
        const gchar *out_codeset;
        EncodingType encoding;
 
-       if ((fp = fopen(file, "w")) == NULL) {
+       if ((fp = fopen(file, "wb")) == NULL) {
                FILE_OP_ERROR(file, "fopen");
                return -1;
        }
@@ -3097,7 +3132,8 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
        chars = gtk_editable_get_chars(GTK_EDITABLE(compose->text), 0, -1);
        len = strlen(chars);
        if (is_ascii_str(chars)) {
-               buf = g_strdup(chars);
+               buf = chars;
+               chars = NULL;
                out_codeset = CS_US_ASCII;
                encoding = ENC_7BIT;
        } else {
@@ -3119,14 +3155,36 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
 
                buf = conv_codeset_strdup(chars, src_codeset, out_codeset);
                if (!buf) {
-                       g_free(chars);
+                       AlertValue aval;
+
+                       aval = alertpanel
+                               (_("Error"),
+                                _("Can't convert the character encoding of the message.\n"
+                                  "Send it anyway?"), _("Yes"), _("+No"), NULL);
+                       if (aval != G_ALERTDEFAULT) {
+                               g_free(chars);
+                               fclose(fp);
+                               unlink(file);
+                               return -1;
+                       } else {
+                               buf = chars;
+                               chars = NULL;
+                       }
+               }
+       }
+       g_free(chars);
+
+#if USE_GPGME
+       if (!is_draft && compose->use_signing && compose->account->clearsign) {
+               if (compose_clearsign_text(compose, &buf) < 0) {
+                       g_warning("clearsign failed\n");
                        fclose(fp);
                        unlink(file);
-                       alertpanel_error(_("Can't convert the codeset of the message."));
+                       g_free(buf);
                        return -1;
                }
        }
-       g_free(chars);
+#endif
 
        /* write headers */
        if (compose_write_headers
@@ -3163,7 +3221,7 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
 
                for (i = 0; i < len; i += B64_LINE_SIZE) {
                        l = MIN(B64_LINE_SIZE, len - i);
-                       to64frombits(outbuf, buf + i, l);
+                       base64_encode(outbuf, buf + i, l);
                        fputs(outbuf, fp);
                        fputc('\n', fp);
                }
@@ -3186,18 +3244,29 @@ static gint compose_write_to_file(Compose *compose, const gchar *file,
        }
 
 #if USE_GPGME
-       if (compose->use_signing) {
+       if (is_draft)
+               return 0;
+
+       if ((compose->use_signing && !compose->account->clearsign) ||
+           compose->use_encryption) {
+               if (canonicalize_file_replace(file) < 0) {
+                       unlink(file);
+                       return -1;
+               }
+       }
+
+       if (compose->use_signing && !compose->account->clearsign) {
                GSList *key_list;
-               
-               if (compose_create_signers_list(compose, &key_list) == -1 ||
-                       rfc2015_sign(file, key_list) < 0) {
-                   
+
+               if (compose_create_signers_list(compose, &key_list) < 0 ||
+                   rfc2015_sign(file, key_list) < 0) {
                        unlink(file);
                        return -1;
                }
        }
        if (compose->use_encryption) {
-               if (rfc2015_encrypt(file, compose->to_list, compose->account->ascii_armored) < 0) {
+               if (rfc2015_encrypt(file, compose->to_list,
+                                   compose->account->ascii_armored) < 0) {
                        unlink(file);
                        return -1;
                }
@@ -3213,7 +3282,7 @@ static gint compose_write_body_to_file(Compose *compose, const gchar *file)
        size_t len;
        gchar *chars;
 
-       if ((fp = fopen(file, "w")) == NULL) {
+       if ((fp = fopen(file, "wb")) == NULL) {
                FILE_OP_ERROR(file, "fopen");
                return -1;
        }
@@ -3246,43 +3315,6 @@ static gint compose_write_body_to_file(Compose *compose, const gchar *file)
        return 0;
 }
 
-static gint compose_save_to_outbox(Compose *compose, const gchar *file)
-{
-       FolderItem *outbox;
-       gchar *path;
-       gint num;
-       FILE *fp;
-
-       debug_print(_("saving sent message...\n"));
-
-       outbox = folder_get_default_outbox();
-       path = folder_item_get_path(outbox);
-       if (!is_dir_exist(path))
-               make_dir_hier(path);
-
-       folder_item_scan(outbox);
-       if ((num = folder_item_add_msg(outbox, file, FALSE)) < 0) {
-               g_free(path);
-               g_warning(_("can't save message\n"));
-               return -1;
-       }
-
-       if ((fp = procmsg_open_mark_file(path, TRUE)) == NULL)
-               g_warning(_("can't open mark file\n"));
-       else {
-               MsgInfo newmsginfo;
-
-               newmsginfo.msgnum = num;
-               newmsginfo.flags.perm_flags = 0;
-               newmsginfo.flags.tmp_flags = 0;
-               procmsg_write_flags(&newmsginfo, fp);
-               fclose(fp);
-       }
-       g_free(path);
-
-       return 0;
-}
-
 static gint compose_remove_reedit_target(Compose *compose)
 {
        FolderItem *item;
@@ -3294,7 +3326,6 @@ static gint compose_remove_reedit_target(Compose *compose)
        item = msginfo->folder;
        g_return_val_if_fail(item != NULL, -1);
 
-       folder_item_scan(item);
        if (procmsg_msg_exist(msginfo) &&
            (item->stype == F_DRAFT || item->stype == F_QUEUE)) {
                if (folder_item_remove_msg(item, msginfo->msgnum) < 0) {
@@ -3306,11 +3337,14 @@ static gint compose_remove_reedit_target(Compose *compose)
        return 0;
 }
 
-
 static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
+{
+       return compose_queue_sub (compose, msgnum, item, FALSE);
+}
+static gint compose_queue_sub(Compose *compose, gint *msgnum, FolderItem **item, gboolean check_subject)
 {
        FolderItem *queue;
-       gchar *tmp, *tmp2, *queue_path;
+       gchar *tmp, *tmp2;
        FILE *fp, *src_fp;
        GSList *cur;
        gchar buf[BUFFSIZE];
@@ -3318,18 +3352,17 @@ static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
         static gboolean lock = FALSE;
        PrefsAccount *mailac = NULL, *newsac = NULL;
        
-       debug_print(_("queueing message...\n"));
+       debug_print("queueing message...\n");
        g_return_val_if_fail(compose->account != NULL, -1);
         g_return_val_if_fail(compose->orig_account != NULL, -1);
 
         lock = TRUE;
        
-        if(!compose_check_for_valid_recipient(compose)) {
-                alertpanel_error(_("Recipient is not specified."));
+       if (compose_check_entries(compose, check_subject) == FALSE) {
                 lock = FALSE;
                 return -1;
-        }
-                                                                       
+       }
+
        if (!compose->to_list && !compose->newsgroup_list) {
                g_warning(_("can't get recipient list."));
                lock = FALSE;
@@ -3367,8 +3400,8 @@ static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
        tmp2 = g_strdup_printf("%s%ctmp%d", g_get_tmp_dir(),
                                      G_DIR_SEPARATOR, (gint)compose);
 
-       if (compose->bounce_filename != NULL) {
-               if (compose_bounce_write_to_file(compose, tmp2) < 0) {
+       if (compose->redirect_filename != NULL) {
+               if (compose_redirect_write_to_file(compose, tmp2) < 0) {
                        unlink(tmp2);
                        lock = FALSE;
                        return -1;
@@ -3384,13 +3417,13 @@ static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
 
        /* add queue header */
        tmp = g_strdup_printf("%s%cqueue.%d", g_get_tmp_dir(),
-                                     G_DIR_SEPARATOR, (gint)compose);
-       if ((fp = fopen(tmp, "w")) == NULL) {
+                             G_DIR_SEPARATOR, (gint)compose);
+       if ((fp = fopen(tmp, "wb")) == NULL) {
                FILE_OP_ERROR(tmp, "fopen");
                g_free(tmp);
                return -1;
        }
-       if ((src_fp = fopen(tmp2, "r")) == NULL) {
+       if ((src_fp = fopen(tmp2, "rb")) == NULL) {
                FILE_OP_ERROR(tmp2, "fopen");
                fclose(fp);
                unlink(tmp);
@@ -3453,11 +3486,19 @@ static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
        }
        /* Save copy folder */
        if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn))) {
-               gchar *str;
+               gchar *savefolderid;
+               
+               savefolderid = gtk_editable_get_chars(GTK_EDITABLE(compose->savemsg_entry), 0, -1);
+               fprintf(fp, "SCF:%s\n", savefolderid);
+               g_free(savefolderid);
+       }
+       /* Message-ID of message replying to */
+       if((compose->replyinfo != NULL) && (compose->replyinfo->msgid != NULL)) {
+               gchar *folderid;
                
-               str = gtk_editable_get_chars(GTK_EDITABLE(compose->savemsg_entry), 0, -1);
-               fprintf(fp, "SCF:%s\n", str);
-               g_free(str);
+               folderid = folder_item_get_identifier(compose->replyinfo->folder);
+               fprintf(fp, "RMID:%s\x7f%d\x7f%s\n", folderid, compose->replyinfo->msgnum, compose->replyinfo->msgid);
+               g_free(folderid);
        }
        fprintf(fp, "\n");
 
@@ -3482,19 +3523,19 @@ static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
                g_free(tmp2);
                return -1;
        }
-                                               
-       /* queue message */
-       queue = folder_get_default_queue();
 
+       queue = account_get_special_folder(compose->account, F_QUEUE);
+       if (!queue) {
+               g_warning(_("can't find queue folder\n"));
+               unlink(tmp);
+               g_free(tmp);
+               return -1;
+       }
        folder_item_scan(queue);
-       queue_path = folder_item_get_path(queue);
-       if (!is_dir_exist(queue_path))
-               make_dir_hier(queue_path);
        if ((num = folder_item_add_msg(queue, tmp, TRUE)) < 0) {
                g_warning(_("can't queue the message\n"));
                unlink(tmp);
                g_free(tmp);
-               g_free(queue_path);
                return -1;
        }
        unlink(tmp);
@@ -3510,20 +3551,6 @@ static gint compose_queue(Compose *compose, gint *msgnum, FolderItem **item)
                                (compose->targetinfo->folder, TRUE);
        }
 
-       if ((fp = procmsg_open_mark_file(queue_path, TRUE)) == NULL)
-               g_warning(_("can't open mark file\n"));
-       else {
-               MsgInfo newmsginfo;
-
-               newmsginfo.msgnum = num;
-               newmsginfo.flags.perm_flags = 0;
-               newmsginfo.flags.tmp_flags = 0;
-               procmsg_write_flags(&newmsginfo, fp);
-               fclose(fp);
-       }
-       g_free(queue_path);
-
-       folder_item_scan(queue);
        folderview_update_item(queue, TRUE);
 
        if((msgnum != NULL) && (item != NULL)) {
@@ -3545,7 +3572,10 @@ static void compose_write_attach(Compose *compose, FILE *fp)
 
        for (row = 0; (ainfo = gtk_clist_get_row_data(clist, row)) != NULL;
             row++) {
-               if ((attach_fp = fopen(ainfo->file, "r")) == NULL) {
+               gchar buf[BUFFSIZE];
+               gchar inbuf[B64_LINE_SIZE], outbuf[B64_BUFFSIZE];
+
+               if ((attach_fp = fopen(ainfo->file, "rb")) == NULL) {
                        g_warning(_("Can't open file %s\n"), ainfo->file);
                        continue;
                }
@@ -3568,28 +3598,33 @@ static void compose_write_attach(Compose *compose, FILE *fp)
                fprintf(fp, "Content-Transfer-Encoding: %s\n\n",
                        procmime_get_encoding_str(ainfo->encoding));
 
-               if (ainfo->encoding == ENC_7BIT) {
-                       gchar buf[BUFFSIZE];
+               switch (ainfo->encoding) {
+
+               case ENC_7BIT:
+               case ENC_8BIT:
+                       /* if (ainfo->encoding == ENC_7BIT) { */
 
                        while (fgets(buf, sizeof(buf), attach_fp) != NULL) {
                                strcrchomp(buf);
                                fputs(buf, fp);
                        }
-               } else {
-                       gchar inbuf[B64_LINE_SIZE], outbuf[B64_BUFFSIZE];
+                       break;
+                       /* } else { */
+               case ENC_BASE64:
 
                        while ((len = fread(inbuf, sizeof(gchar),
                                            B64_LINE_SIZE, attach_fp))
                               == B64_LINE_SIZE) {
-                               to64frombits(outbuf, inbuf, B64_LINE_SIZE);
+                               base64_encode(outbuf, inbuf, B64_LINE_SIZE);
                                fputs(outbuf, fp);
                                fputc('\n', fp);
                        }
                        if (len > 0 && feof(attach_fp)) {
-                               to64frombits(outbuf, inbuf, len);
+                               base64_encode(outbuf, inbuf, len);
                                fputs(outbuf, fp);
                                fputc('\n', fp);
                        }
+                       break;
                }
 
                fclose(attach_fp);
@@ -3598,6 +3633,37 @@ static void compose_write_attach(Compose *compose, FILE *fp)
        fprintf(fp, "\n--%s--\n", compose->boundary);
 }
 
+#define QUOTE_IF_REQUIRED(out, str)                    \
+{                                                      \
+       if (*str != '"' && (strchr(str, ',')            \
+                       || strchr(str, '.'))) {         \
+               gchar *__tmp;                           \
+               gint len;                               \
+                                                       \
+               len = strlen(str) + 3;                  \
+               Xalloca(__tmp, len, return -1);         \
+               g_snprintf(__tmp, len, "\"%s\"", str);  \
+               out = __tmp;                            \
+       } else {                                        \
+               Xstrdup_a(out, str, return -1);         \
+       }                                               \
+}
+
+#define PUT_RECIPIENT_HEADER(header, str)                                   \
+{                                                                           \
+       if (*str != '\0') {                                                  \
+               Xstrdup_a(str, str, return -1);                              \
+               g_strstrip(str);                                             \
+               if (*str != '\0') {                                          \
+                       compose->to_list = address_list_append               \
+                               (compose->to_list, str);                     \
+                       compose_convert_header                               \
+                               (buf, sizeof(buf), str, strlen(header) + 2); \
+                       fprintf(fp, "%s: %s\n", header, buf);                \
+               }                                                            \
+       }                                                                    \
+}
+
 #define IS_IN_CUSTOM_HEADER(header) \
        (compose->account->add_customhdr && \
         custom_header_find(compose->account->customhdr_list, header) != NULL)
@@ -3617,7 +3683,7 @@ static gint compose_write_headers_from_headerlist(Compose *compose,
                return 0;
        }
 
-       debug_print(_("Writing %s-header\n"), header);
+       debug_print("Writing %s-header\n", header);
 
        header_w_colon = g_strconcat(header, ":", NULL);
        trans_hdr = (prefs_common.trans_hdr ? gettext(header_w_colon) : header_w_colon);
@@ -3660,6 +3726,7 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
 {
        gchar buf[BUFFSIZE];
        gchar *str;
+       gchar *name;
        /* struct utsname utsbuf; */
 
        g_return_val_if_fail(fp != NULL, -1);
@@ -3679,8 +3746,9 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                        compose_convert_header
                                (buf, sizeof(buf), compose->account->name,
                                 strlen("From: "));
+                       QUOTE_IF_REQUIRED(name, buf);
                        fprintf(fp, "From: %s <%s>\n",
-                               buf, compose->account->address);
+                               name, compose->account->address);
                } else
                        fprintf(fp, "From: %s\n", compose->account->address);
        }
@@ -3690,20 +3758,7 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
 #if 0 /* NEW COMPOSE GUI */
        if (compose->use_to) {
                str = gtk_entry_get_text(GTK_ENTRY(compose->to_entry));
-               if (*str != '\0') {
-                       Xstrdup_a(str, str, return -1);
-                       g_strstrip(str);
-                       if (*str != '\0') {
-                               compose->to_list = address_list_append
-                                       (compose->to_list, str);
-                               if (!IS_IN_CUSTOM_HEADER("To")) {
-                                       compose_convert_header
-                                               (buf, sizeof(buf), str,
-                                                strlen("To: "));
-                                       fprintf(fp, "To: %s\n", buf);
-                               }
-                       }
-               }
+               PUT_RECIPIENT_HEADER("To", str);
        }
 #endif
 
@@ -3719,11 +3774,9 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                        compose->newsgroup_list =
                                newsgroup_list_append(compose->newsgroup_list,
                                                      str);
-                       if (!IS_IN_CUSTOM_HEADER("Newsgroups")) {
-                               compose_convert_header(buf, sizeof(buf), str,
-                                                      strlen("Newsgroups: "));
-                               fprintf(fp, "Newsgroups: %s\n", buf);
-                       }
+                       compose_convert_header(buf, sizeof(buf), str,
+                                              strlen("Newsgroups: "));
+                       fprintf(fp, "Newsgroups: %s\n", buf);
                }
        }
 #endif
@@ -3732,20 +3785,7 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
 #if 0 /* NEW COMPOSE GUI */
        if (compose->use_cc) {
                str = gtk_entry_get_text(GTK_ENTRY(compose->cc_entry));
-               if (*str != '\0') {
-                       Xstrdup_a(str, str, return -1);
-                       g_strstrip(str);
-                       if (*str != '\0') {
-                               compose->to_list = address_list_append
-                                       (compose->to_list, str);
-                               if (!IS_IN_CUSTOM_HEADER("Cc")) {
-                                       compose_convert_header
-                                               (buf, sizeof(buf), str,
-                                                strlen("Cc: "));
-                                       fprintf(fp, "Cc: %s\n", buf);
-                               }
-                       }
-               }
+               PUT_RECIPIENT_HEADER("Cc", str);
        }
 #endif
        /* Bcc */
@@ -3753,17 +3793,7 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
 #if 0 /* NEW COMPOSE GUI */
        if (compose->use_bcc) {
                str = gtk_entry_get_text(GTK_ENTRY(compose->bcc_entry));
-               if (*str != '\0') {
-                       Xstrdup_a(str, str, return -1);
-                       g_strstrip(str);
-                       if (*str != '\0') {
-                               compose->to_list = address_list_append
-                                       (compose->to_list, str);
-                               compose_convert_header(buf, sizeof(buf), str,
-                                                      strlen("Bcc: "));
-                               fprintf(fp, "Bcc: %s\n", buf);
-                       }
-               }
+               PUT_RECIPIENT_HEADER("Bcc", str);
        }
 #endif
 
@@ -3842,14 +3872,14 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                fprintf(fp, "X-Mailer: %s (GTK+ %d.%d.%d; %s)\n",
                        prog_version,
                        gtk_major_version, gtk_minor_version, gtk_micro_version,
-                       HOST_ALIAS);
+                       TARGET_ALIAS);
                        /* utsbuf.sysname, utsbuf.release, utsbuf.machine); */
        }
        if (g_slist_length(compose->newsgroup_list) && !IS_IN_CUSTOM_HEADER("X-Newsreader")) {
                fprintf(fp, "X-Newsreader: %s (GTK+ %d.%d.%d; %s)\n",
                        prog_version,
                        gtk_major_version, gtk_minor_version, gtk_micro_version,
-                       HOST_ALIAS);
+                       TARGET_ALIAS);
                        /* utsbuf.sysname, utsbuf.release, utsbuf.machine); */
        }
 
@@ -3898,6 +3928,25 @@ static gint compose_write_headers(Compose *compose, FILE *fp,
                        procmime_get_encoding_str(encoding));
        }
 
+       /* PRIORITY */
+       switch (compose->priority) {
+               case PRIORITY_HIGHEST: fprintf(fp, "Importance: high\n"
+                                                  "X-Priority: 1 (Highest)\n");
+                       break;
+               case PRIORITY_HIGH: fprintf(fp, "Importance: high\n"
+                                               "X-Priority: 2 (High)\n");
+                       break;
+               case PRIORITY_NORMAL: break;
+               case PRIORITY_LOW: fprintf(fp, "Importance: low\n"
+                                              "X-Priority: 4 (Low)\n");
+                       break;
+               case PRIORITY_LOWEST: fprintf(fp, "Importance: low\n"
+                                                 "X-Priority: 5 (Lowest)\n");
+                       break;
+               default: debug_print("compose: priority unknown : %d\n",
+                                    compose->priority);
+       }
+
        /* Request Return Receipt */
        if (!IS_IN_CUSTOM_HEADER("Disposition-Notification-To")) {
                if (compose->return_receipt) {
@@ -3962,41 +4011,11 @@ static void compose_generate_msgid(Compose *compose, gchar *buf, gint len)
                   lt->tm_min, lt->tm_sec,
                   (guint)random(), addr);
 
-       debug_print(_("generated Message-ID: %s\n"), buf);
+       debug_print("generated Message-ID: %s\n", buf);
 
        g_free(addr);
 }
 
-static void compose_add_entry_field(GtkWidget *table, GtkWidget **hbox,
-                                   GtkWidget **entry, gint *count,
-                                   const gchar *label_str,
-                                   gboolean is_addr_entry)
-{
-       GtkWidget *label;
-
-       if (GTK_TABLE(table)->nrows < (*count) + 1)
-               gtk_table_resize(GTK_TABLE(table), (*count) + 1, 2);
-
-       *hbox = gtk_hbox_new(FALSE, 0);
-       label = gtk_label_new
-               (prefs_common.trans_hdr ? gettext(label_str) : label_str);
-       gtk_box_pack_end(GTK_BOX(*hbox), label, FALSE, FALSE, 0);
-       gtk_table_attach(GTK_TABLE(table), *hbox, 0, 1, *count, (*count) + 1,
-                        GTK_FILL, 0, 2, 0);
-       *entry = gtk_entry_new_with_max_length(MAX_ENTRY_LENGTH);
-       gtk_table_attach
-               (GTK_TABLE(table), *entry, 1, 2, *count, (*count) + 1, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
-#if 0 /* NEW COMPOSE GUI */
-       if (GTK_TABLE(table)->nrows > (*count) + 1)
-               gtk_table_set_row_spacing(GTK_TABLE(table), *count, 4);
-#endif
-
-       if (is_addr_entry)
-               address_completion_register_entry(GTK_ENTRY(*entry));
-
-       (*count)++;
-}
-
 static void compose_create_header_entry(Compose *compose) 
 {
        gchar *headers[] = {"To:", "Cc:", "Bcc:", "Newsgroups:", "Reply-To:", "Followup-To:", NULL};
@@ -4277,7 +4296,7 @@ static GtkWidget *compose_create_others(Compose *compose)
        savemsg_checkbtn = gtk_check_button_new_with_label(_("Save Message to "));
        gtk_widget_show(savemsg_checkbtn);
        gtk_table_attach(GTK_TABLE(table), savemsg_checkbtn, 0, 1, rowcount, rowcount + 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 0, 0);
-       if(folder_get_default_outbox()) {
+       if(account_get_special_folder(compose->account, F_OUTBOX)) {
                gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(savemsg_checkbtn), prefs_common.savemsg);
        }
        gtk_signal_connect(GTK_OBJECT(savemsg_checkbtn), "toggled",
@@ -4287,8 +4306,9 @@ static GtkWidget *compose_create_others(Compose *compose)
        gtk_widget_show(savemsg_entry);
        gtk_table_attach_defaults(GTK_TABLE(table), savemsg_entry, 1, 2, rowcount, rowcount + 1);
        gtk_editable_set_editable(GTK_EDITABLE(savemsg_entry), prefs_common.savemsg);
-       if(folder_get_default_outbox()) {
-               folderidentifier = folder_item_get_identifier(folder_get_default_outbox());
+       if(account_get_special_folder(compose->account, F_OUTBOX)) {
+               folderidentifier = folder_item_get_identifier(account_get_special_folder
+                                 (compose->account, F_OUTBOX));
                gtk_entry_set_text(GTK_ENTRY(savemsg_entry), folderidentifier);
                g_free(folderidentifier);
        }
@@ -4353,8 +4373,6 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        GtkWidget *scrolledwin;
        GtkWidget *text;
 
-       GtkWidget *table;
-
        UndoMain *undostruct;
 
        gchar *titles[N_ATTACH_COLS];
@@ -4375,9 +4393,11 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
         GtkPspell * gtkpspell = NULL;
 #endif
 
+       static GdkGeometry geometry;
+
        g_return_val_if_fail(account != NULL, NULL);
 
-       debug_print(_("Creating compose window...\n"));
+       debug_print("Creating compose window...\n");
        compose = g_new0(Compose, 1);
 
        titles[COL_MIMETYPE] = _("MIME type");
@@ -4391,14 +4411,19 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
        gtk_widget_set_usize(window, -1, prefs_common.compose_height);
        gtk_window_set_wmclass(GTK_WINDOW(window), "compose window", "Sylpheed");
+
+       if (!geometry.max_width) {
+               geometry.max_width = gdk_screen_width();
+               geometry.max_height = gdk_screen_height();
+       }
+       gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL,
+                                     &geometry, GDK_HINT_MAX_SIZE);
+
        gtk_signal_connect(GTK_OBJECT(window), "delete_event",
                           GTK_SIGNAL_FUNC(compose_delete_cb), compose);
        gtk_signal_connect(GTK_OBJECT(window), "destroy",
                           GTK_SIGNAL_FUNC(compose_destroy_cb), compose);
-       gtk_signal_connect(GTK_OBJECT(window), "focus_in_event",
-                          GTK_SIGNAL_FUNC(manage_window_focus_in), NULL);
-       gtk_signal_connect(GTK_OBJECT(window), "focus_out_event",
-                          GTK_SIGNAL_FUNC(manage_window_focus_out), NULL);
+       MANAGE_WINDOW_SIGNALS_CONNECT(window);
        gtk_widget_realize(window);
 
        gtkut_widget_set_composer_icon(window);
@@ -4504,6 +4529,8 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
                           GTK_SIGNAL_FUNC(compose_grab_focus_cb), compose);
        gtk_signal_connect(GTK_OBJECT(text), "activate",
                           GTK_SIGNAL_FUNC(text_activated), compose);
+       gtk_signal_connect(GTK_OBJECT(text), "insert_text",
+                          GTK_SIGNAL_FUNC(text_inserted), compose);
        gtk_signal_connect_after(GTK_OBJECT(text), "button_press_event",
                                 GTK_SIGNAL_FUNC(compose_button_press_cb),
                                 edit_vbox);
@@ -4547,9 +4574,6 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
                new_style = gtk_style_copy(style);
 
        if (prefs_common.textfont) {
-               CharSet charset;
-
-               charset = conv_get_current_charset();
                if (MB_CUR_MAX == 1) {
                        gchar *fontstr, *p;
 
@@ -4586,7 +4610,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        menu_set_sensitive(ifactory, "/Edit/Undo", FALSE);
        menu_set_sensitive(ifactory, "/Edit/Redo", FALSE);
 
-       tmpl_menu = gtk_item_factory_get_item(ifactory, "/Tool/Template");
+       tmpl_menu = gtk_item_factory_get_item(ifactory, "/Tools/Template");
 #if 0 /* NEW COMPOSE GUI */
        gtk_widget_hide(bcc_hbox);
        gtk_widget_hide(bcc_entry);
@@ -4614,7 +4638,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        }
 #endif
 
-       update_compose_actions_menu(ifactory, "/Edit/Actions", compose);
+       update_compose_actions_menu(ifactory, "/Tools/Actions", compose);
 
 
        undostruct = undo_init(text);
@@ -4670,6 +4694,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        compose->modified = FALSE;
 
        compose->return_receipt = FALSE;
+       compose->paste_as_quotation = FALSE;
 
        compose->to_list        = NULL;
        compose->newsgroup_list = NULL;
@@ -4679,7 +4704,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        compose->exteditor_readdes = -1;
        compose->exteditor_tag     = -1;
 
-       compose->bounce_filename = NULL;
+       compose->redirect_filename = NULL;
        compose->undostruct = undostruct;
 #if USE_PSPELL
        
@@ -4699,7 +4724,7 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
                        GtkWidget *menuitem;
 
                        if (!gtkpspell_set_sug_mode(gtkpspell, prefs_common.pspell_sugmode)) {
-                               debug_print(_("Pspell: could not set suggestion mode %s"),
+                               debug_print("Pspell: could not set suggestion mode %s\n",
                                    gtkpspellcheckers->error_message);
                                gtkpspell_checkers_reset_error();
                        }
@@ -4821,6 +4846,10 @@ static Compose *compose_create(PrefsAccount *account, ComposeMode mode)
        if (!prefs_common.show_ruler)
                gtk_widget_hide(ruler_hbox);
 
+       /* Priority */
+       compose->priority = PRIORITY_NORMAL;
+       compose_update_priority_menu_item(compose);
+
        select_account(compose, account);
        set_toolbar_style(compose);
 
@@ -4966,8 +4995,13 @@ static GtkWidget *compose_account_option_menu_create(Compose *compose)
 
                if (ac == compose->account) def_menu = num;
 
-               name = g_strdup_printf("%s: %s <%s>",
-                                      ac->account_name, ac->name, ac->address);
+               if (ac->name)
+                       name = g_strdup_printf("%s: %s <%s>",
+                                              ac->account_name,
+                                              ac->name, ac->address);
+               else
+                       name = g_strdup_printf("%s: %s",
+                                              ac->account_name, ac->address);
                MENUITEM_ADD(menu, menuitem, name, ac);
                g_free(name);
                gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
@@ -4981,6 +5015,46 @@ static GtkWidget *compose_account_option_menu_create(Compose *compose)
        return hbox;
 }
 
+static void compose_set_priority_cb(gpointer data,
+                                   guint action,
+                                   GtkWidget *widget)
+{
+       Compose *compose = (Compose *) data;
+       compose->priority = action;
+}
+
+static void compose_update_priority_menu_item(Compose * compose)
+{
+       GtkItemFactory *ifactory;
+       GtkWidget *menuitem = NULL;
+
+       ifactory = gtk_item_factory_from_widget(compose->menubar);
+       
+       switch (compose->priority) {
+               case PRIORITY_HIGHEST:
+                       menuitem = gtk_item_factory_get_item
+                               (ifactory, "/Message/Priority/Highest");
+                       break;
+               case PRIORITY_HIGH:
+                       menuitem = gtk_item_factory_get_item
+                               (ifactory, "/Message/Priority/High");
+                       break;
+               case PRIORITY_NORMAL:
+                       menuitem = gtk_item_factory_get_item
+                               (ifactory, "/Message/Priority/Normal");
+                       break;
+               case PRIORITY_LOW:
+                       menuitem = gtk_item_factory_get_item
+                               (ifactory, "/Message/Priority/Low");
+                       break;
+               case PRIORITY_LOWEST:
+                       menuitem = gtk_item_factory_get_item
+                               (ifactory, "/Message/Priority/Lowest");
+                       break;
+       }
+       gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), TRUE);
+}      
 static void compose_set_template_menu(Compose *compose)
 {
        GSList *tmpl_list, *cur;
@@ -5032,8 +5106,8 @@ void compose_reflect_prefs_pixmap_theme(void)
        }
 }
 
-
-static void compose_template_apply(Compose *compose, Template *tmpl)
+static void compose_template_apply(Compose *compose, Template *tmpl,
+                                  gboolean replace)
 {
        gchar *qmark;
        gchar *parsed_str;
@@ -5048,14 +5122,12 @@ static void compose_template_apply(Compose *compose, Template *tmpl)
        if (tmpl->to && *tmpl->to != '\0')
                compose_entry_append(compose, tmpl->to, COMPOSE_TO);
 
-       gtk_stext_clear(GTK_STEXT(compose->text));
+       if (replace)
+               gtk_stext_clear(GTK_STEXT(compose->text));
 
        if (compose->replyinfo == NULL) {
-               MsgInfo dummyinfo;
-
-               memset(&dummyinfo, 0, sizeof(MsgInfo));
-               parsed_str = compose_quote_fmt(compose, &dummyinfo,
-                                              tmpl->value, NULL, NULL);
+               parsed_str = compose_quote_fmt(compose, NULL, tmpl->value,
+                                              NULL, NULL);
        } else {
                if (prefs_common.quotemark && *prefs_common.quotemark)
                        qmark = prefs_common.quotemark;
@@ -5066,9 +5138,17 @@ static void compose_template_apply(Compose *compose, Template *tmpl)
                                               tmpl->value, qmark, NULL);
        }
 
-       if (parsed_str && prefs_common.auto_sig)
+       if (replace && parsed_str && prefs_common.auto_sig)
                compose_insert_sig(compose);
 
+       if (replace && parsed_str) {
+               gtk_editable_set_position(GTK_EDITABLE(compose->text), 0);
+               gtk_stext_set_point(GTK_STEXT(compose->text), 0);
+       }
+
+       if (parsed_str)
+               compose_changed_cb(NULL, compose);
+
        gtk_stext_thaw(GTK_STEXT(compose->text));
 }
 
@@ -5103,8 +5183,8 @@ static void compose_destroy(Compose *compose)
        g_free(compose->msgid);
        g_free(compose->boundary);
 
-       if (compose->bounce_filename)
-               g_free(compose->bounce_filename);
+       if (compose->redirect_filename)
+               g_free(compose->redirect_filename);
 
        g_free(compose->exteditor_file);
 
@@ -5364,13 +5444,19 @@ static void compose_attach_property_create(gboolean *cancelled)
                         GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
 
        optmenu = gtk_option_menu_new();
-       gtk_box_pack_start(GTK_BOX(hbox), optmenu, FALSE, FALSE, 0);
+       gtk_box_pack_start(GTK_BOX(hbox), optmenu, TRUE, TRUE, 0);
 
        optmenu_menu = gtk_menu_new();
        MENUITEM_ADD(optmenu_menu, menuitem, "7bit", ENC_7BIT);
+       gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), optmenu_menu);
+#if 0
        gtk_widget_set_sensitive(menuitem, FALSE);
+#endif
        MENUITEM_ADD(optmenu_menu, menuitem, "8bit", ENC_8BIT);
+       gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), optmenu_menu);
+#if 0
        gtk_widget_set_sensitive(menuitem, FALSE);
+#endif
        MENUITEM_ADD(optmenu_menu, menuitem, "quoted-printable", ENC_QUOTED_PRINTABLE);
        gtk_widget_set_sensitive(menuitem, FALSE);
        MENUITEM_ADD(optmenu_menu, menuitem, "base64", ENC_BASE64);
@@ -5437,20 +5523,22 @@ static void attach_property_key_pressed(GtkWidget *widget, GdkEventKey *event,
 
 static void compose_exec_ext_editor(Compose *compose)
 {
-       gchar tmp[64];
+       gchar *tmp;
        pid_t pid;
        gint pipe_fds[2];
 
-       g_snprintf(tmp, sizeof(tmp), "%s%ctmpmsg.%08x",
-                  g_get_tmp_dir(), G_DIR_SEPARATOR, (gint)compose);
+       tmp = g_strdup_printf("%s%ctmpmsg.%08x", get_tmp_dir(),
+                             G_DIR_SEPARATOR, (gint)compose);
 
        if (pipe(pipe_fds) < 0) {
                perror("pipe");
+               g_free(tmp);
                return;
        }
 
        if ((pid = fork()) < 0) {
                perror("fork");
+               g_free(tmp);
                return;
        }
 
@@ -5495,6 +5583,8 @@ static void compose_exec_ext_editor(Compose *compose)
                close(pipe_fds[1]);
                _exit(0);
        }
+
+       g_free(tmp);
 }
 
 static gint compose_exec_ext_editor_real(const gchar *file)
@@ -5589,7 +5679,7 @@ static void compose_input_cb(gpointer data, gint source,
        Compose *compose = (Compose *)data;
        gint i = 0;
 
-       debug_print(_("Compose: input from monitoring process\n"));
+       debug_print("Compose: input from monitoring process\n");
 
        gdk_input_remove(compose->exteditor_tag);
 
@@ -5831,6 +5921,10 @@ static void toolbar_address_cb(GtkWidget *widget, gpointer data)
 
 static void select_account(Compose * compose, PrefsAccount * ac)
 {
+#if USE_GPGME
+       GtkItemFactory *ifactory;
+       GtkWidget *menuitem;
+#endif /* USE_GPGME */
        compose->account = ac;
        compose_set_title(compose);
 
@@ -5905,6 +5999,30 @@ static void select_account(Compose * compose, PrefsAccount * ac)
                }
                gtk_widget_queue_resize(compose->table_vbox);
 #endif
+#if USE_GPGME
+               ifactory = gtk_item_factory_from_widget(compose->menubar);
+                       menu_set_sensitive(ifactory,
+                                          "/Message/Sign", TRUE);
+                       menu_set_sensitive(ifactory,
+                                          "/Message/Encrypt", TRUE);
+
+                       menuitem = gtk_item_factory_get_item(ifactory, "/Message/Sign");
+               if (ac->default_sign)
+                       gtk_check_menu_item_set_active
+                               (GTK_CHECK_MENU_ITEM(menuitem), TRUE);
+               else
+                       gtk_check_menu_item_set_active
+                               (GTK_CHECK_MENU_ITEM(menuitem), FALSE);
+
+                       menuitem = gtk_item_factory_get_item(ifactory, "/Message/Encrypt");
+               if (ac->default_encrypt)
+                       gtk_check_menu_item_set_active
+                               (GTK_CHECK_MENU_ITEM(menuitem), TRUE);
+               else
+                       gtk_check_menu_item_set_active
+                               (GTK_CHECK_MENU_ITEM(menuitem), FALSE);
+#endif /* USE_GPGME */
+
 }
 
 static void account_activated(GtkMenuItem *menuitem, gpointer data)
@@ -5972,6 +6090,12 @@ static void compose_send_cb(gpointer data, guint action, GtkWidget *widget)
 {
        Compose *compose = (Compose *)data;
        gint val;
+       
+       if (prefs_common.work_offline)
+               if (alertpanel(_("Offline warning"), 
+                              _("You're working offline. Override?"),
+                              _("Yes"), _("No"), NULL) != G_ALERTDEFAULT)
+               return;
 
        val = compose_send(compose);
 
@@ -5984,7 +6108,7 @@ static void compose_send_later_cb(gpointer data, guint action,
        Compose *compose = (Compose *)data;
        gint val;
 
-       val = compose_queue(compose, NULL, NULL);
+       val = compose_queue_sub(compose, NULL, NULL, TRUE);
        if (!val) gtk_widget_destroy(compose->window);
 }
 
@@ -5995,15 +6119,16 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
        gchar *tmp;
        gint msgnum;
        static gboolean lock = FALSE;
-
+       MsgInfo *newmsginfo;
+       
        if (lock) return;
 
-       draft = folder_get_default_draft();
+       draft = account_get_special_folder(compose->account, F_DRAFT);
        g_return_if_fail(draft != NULL);
 
        lock = TRUE;
 
-       tmp = g_strdup_printf("%s%cdraft.%d", g_get_tmp_dir(),
+       tmp = g_strdup_printf("%s%cdraft.%08x", get_tmp_dir(),
                              G_DIR_SEPARATOR, (gint)compose);
 
        if (compose_write_to_file(compose, tmp, TRUE) < 0) {
@@ -6012,8 +6137,7 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                return;
        }
 
-       folder_item_scan(draft);
-       if ((msgnum = folder_item_add_msg(draft, tmp, TRUE)) <= 0) {
+       if ((msgnum = folder_item_add_msg(draft, tmp, TRUE)) < 0) {
                unlink(tmp);
                g_free(tmp);
                lock = FALSE;
@@ -6030,9 +6154,11 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                                               TRUE);
        }
 
-       folder_item_scan(draft);
+       newmsginfo = folder_item_fetch_msginfo(draft, msgnum);
+       procmsg_msginfo_unset_flags(newmsginfo, ~0, ~0);
        folderview_update_item(draft, TRUE);
-
+       procmsg_msginfo_free(newmsginfo);
+       
        lock = FALSE;
 
        /* 0: quit editing  1: keep editing */
@@ -6053,7 +6179,7 @@ static void compose_draft_cb(gpointer data, guint action, GtkWidget *widget)
                g_free(path);
 
                procmsg_msginfo_free(compose->targetinfo);
-               compose->targetinfo = g_new0(MsgInfo, 1);
+               compose->targetinfo = procmsg_msginfo_new();
                compose->targetinfo->msgnum = msgnum;
                compose->targetinfo->size = s.st_size;
                compose->targetinfo->mtime = s.st_mtime;
@@ -6067,7 +6193,7 @@ static void compose_attach_cb(gpointer data, guint action, GtkWidget *widget)
        Compose *compose = (Compose *)data;
        GList *file_list;
 
-       if (compose->bounce_filename != NULL)
+       if (compose->redirect_filename != NULL)
                return;
 
        file_list = filesel_select_multiple_files(_("Select file"), NULL);
@@ -6077,7 +6203,8 @@ static void compose_attach_cb(gpointer data, guint action, GtkWidget *widget)
 
                for ( tmp = file_list; tmp; tmp = tmp->next) {
                        gchar *file = (gchar *) tmp->data;
-                       compose_attach_append(compose, file, MIME_UNKNOWN);
+                       compose_attach_append(compose, file, file, NULL);
+                       compose_changed_cb(NULL, compose);
                        g_free(file);
                }
                g_list_free(file_list);
@@ -6150,11 +6277,22 @@ static void compose_template_activate_cb(GtkWidget *widget, gpointer data)
 {
        Compose *compose = (Compose *)data;
        Template *tmpl;
+       gchar *msg;
+       AlertValue val;
 
        tmpl = gtk_object_get_data(GTK_OBJECT(widget), "template");
        g_return_if_fail(tmpl != NULL);
 
-       compose_template_apply(compose, tmpl);
+       msg = g_strdup_printf(_("Do you want to apply the template `%s' ?"),
+                             tmpl->name);
+       val = alertpanel(_("Apply template"), msg,
+                        _("Replace"), _("Insert"), _("Cancel"));
+       g_free(msg);
+
+       if (val == G_ALERTDEFAULT)
+               compose_template_apply(compose, tmpl, TRUE);
+       else if (val == G_ALERTALTERNATE)
+               compose_template_apply(compose, tmpl, FALSE);
 }
 
 static void compose_ext_editor_cb(gpointer data, guint action,
@@ -6204,19 +6342,23 @@ static void compose_paste_cb(Compose *compose)
                        (GTK_EDITABLE(compose->focused_editable));
 }
 
-static void compose_allsel_cb(Compose *compose)
+static void compose_paste_as_quote_cb(Compose *compose)
 {
        if (compose->focused_editable &&
-           GTK_WIDGET_HAS_FOCUS(compose->focused_editable))
-               gtk_editable_select_region
-                       (GTK_EDITABLE(compose->focused_editable), 0, -1);
+           GTK_WIDGET_HAS_FOCUS(compose->focused_editable)) {
+               compose->paste_as_quotation = TRUE;
+               gtk_editable_paste_clipboard
+                       (GTK_EDITABLE(compose->focused_editable));
+               compose->paste_as_quotation = FALSE;
+       }
 }
 
-static void compose_move_beginning_of_line_cb(Compose *compose)
+static void compose_allsel_cb(Compose *compose)
 {
        if (compose->focused_editable &&
-               GTK_WIDGET_HAS_FOCUS(compose->focused_editable))
-               gtk_stext_move_beginning_of_line(GTK_STEXT(compose->focused_editable));
+           GTK_WIDGET_HAS_FOCUS(compose->focused_editable))
+               gtk_editable_select_region
+                       (GTK_EDITABLE(compose->focused_editable), 0, -1);
 }
 
 static void compose_gtk_stext_action_cb(Compose *compose, ComposeCallGtkSTextAction action)
@@ -6500,8 +6642,10 @@ static void compose_attach_drag_received_cb (GtkWidget           *widget,
 
        list = uri_list_extract_filenames((const gchar *)data->data);
        for (tmp = list; tmp != NULL; tmp = tmp->next)
-               compose_attach_append(compose, (const gchar *)tmp->data,
-                                     MIME_UNKNOWN);
+               compose_attach_append
+                       (compose, (const gchar *)tmp->data,
+                        (const gchar *)tmp->data, NULL);
+       if (list) compose_changed_cb(NULL, compose);
        list_free_strings(list);
        g_list_free(list);
 }
@@ -6666,6 +6810,42 @@ static void text_activated(GtkWidget *widget, Compose *compose)
        compose_send_control_enter(compose);
 }
 
+static void text_inserted(GtkWidget *widget, const gchar *text,
+                         gint length, gint *position, Compose *compose)
+{
+       GtkEditable *editable = GTK_EDITABLE(widget);
+
+       gtk_signal_handler_block_by_func(GTK_OBJECT(widget),
+                                        GTK_SIGNAL_FUNC(text_inserted),
+                                        compose);
+       if (compose->paste_as_quotation) {
+               gchar *new_text;
+               gchar *qmark;
+               gint pos;
+
+               new_text = g_strndup(text, length);
+               if (prefs_common.quotemark && *prefs_common.quotemark)
+                       qmark = prefs_common.quotemark;
+               else
+                       qmark = "> ";
+               gtk_stext_set_point(GTK_STEXT(widget), *position);
+               compose_quote_fmt(compose, NULL, "%Q", qmark, new_text);
+               pos = gtk_stext_get_point(GTK_STEXT(widget));
+               gtk_editable_set_position(editable, pos);
+               *position = pos;
+               g_free(new_text);
+       } else
+               gtk_editable_insert_text(editable, text, length, position);
+
+       if (prefs_common.autowrap)
+               compose_wrap_line_all(compose);
+
+       gtk_signal_handler_unblock_by_func(GTK_OBJECT(widget),
+                                          GTK_SIGNAL_FUNC(text_inserted),
+                                          compose);
+       gtk_signal_emit_stop_by_name(GTK_OBJECT(editable), "insert_text");
+}
+
 static gboolean compose_send_control_enter(Compose *compose)
 {
        GdkEvent *ev;
@@ -6674,6 +6854,9 @@ static gboolean compose_send_control_enter(Compose *compose)
        GtkAccelEntry *accel;
        GtkWidget *send_menu;
        GSList *list;
+       GdkModifierType ignored_mods =
+               (GDK_LOCK_MASK | GDK_MOD2_MASK | GDK_MOD3_MASK |
+                GDK_MOD4_MASK | GDK_MOD5_MASK);
 
        ev = gtk_get_current_event();
        if (ev->type != GDK_KEY_PRESS) return FALSE;
@@ -6687,7 +6870,8 @@ static gboolean compose_send_control_enter(Compose *compose)
        list = gtk_accel_group_entries_from_object(GTK_OBJECT(send_menu));
        accel = (GtkAccelEntry *)list->data;
        if (accel->accelerator_key == kev->keyval &&
-           accel->accelerator_mods == kev->state) {
+           (accel->accelerator_mods & ~ignored_mods) ==
+           (kev->state & ~ignored_mods)) {
                compose_send_cb(compose, 0, NULL);
                return TRUE;
        }